<commit_before>package config

import (
	"bytes"
	"encoding/gob"
	"sync"

	"github.com/hashicorp/hil"
	"github.com/hashicorp/hil/ast"
	"github.com/mitchellh/copystructure"
	"github.com/mitchellh/reflectwalk"
)

// UnknownVariableValue is a sentinel value that can be used
// to denote that the value of a variable is unknown at this time.
// RawConfig uses this information to build up data about
// unknown keys.
const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"

// RawConfig is a structure that holds a piece of configuration
// where te overall structure is unknown since it will be used
// to configure a plugin or some other similar external component.
//
// RawConfigs can be interpolated with variables that come from
// other resources, user variables, etc.
//
// RawConfig supports a query-like interface to request
// information from deep within the structure.
type RawConfig struct {
	Key            string
	Raw            map[string]interface{}
	Interpolations []ast.Node
	Variables      map[string]InterpolatedVariable

	lock        sync.Mutex
	config      map[string]interface{}
	unknownKeys []string
}

// NewRawConfig creates a new RawConfig structure and populates the
// publicly readable struct fields.
func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
	result := &RawConfig{Raw: raw}
	if err := result.init(); err != nil {
		return nil, err
	}

	return result, nil
}

// RawMap returns a copy of the RawConfig.Raw map.
func (r *RawConfig) RawMap() map[string]interface{} {
	r.lock.Lock()
	defer r.lock.Unlock()

	m := make(map[string]interface{})
	for k, v := range r.Raw {
		m[k] = v
	}
	return m
}

// Copy returns a copy of this RawConfig, uninterpolated.
func (r *RawConfig) Copy() *RawConfig {
	if r == nil {
		return nil
	}

	r.lock.Lock()
	defer r.lock.Unlock()

	newRaw := make(map[string]interface{})
	for k, v := range r.Raw {
		newRaw[k] = v
	}

	result, err := NewRawConfig(newRaw)
	if err != nil {
		panic("copy failed: " + err.Error())
	}

	result.Key = r.Key
	return result
}

// Value returns the value of the configuration if this configuration
// has a Key set. If this does not have a Key set, nil will be returned.
func (r *RawConfig) Value() interface{} {
	if c := r.Config(); c != nil {
		if v, ok := c[r.Key]; ok {
			return v
		}
	}

	r.lock.Lock()
	defer r.lock.Unlock()
	return r.Raw[r.Key]
}

// Config returns the entire configuration with the variables
// interpolated from any call to Interpolate.
//
// If any interpolated variables are unknown (value set to
// UnknownVariableValue), the first non-container (map, slice, etc.) element
// will be removed from the config. The keys of unknown variables
// can be found using the UnknownKeys function.
//
// By pruning out unknown keys from the configuration, the raw
// structure will always successfully decode into its ultimate
// structure using something like mapstructure.
func (r *RawConfig) Config() map[string]interface{} {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.config
}

// Interpolate uses the given mapping of variable values and uses
// those as the values to replace any variables in this raw
// configuration.
//
// Any prior calls to Interpolate are replaced with this one.
//
// If a variable key is missing, this will panic.
func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
	r.lock.Lock()
	defer r.lock.Unlock()

	config := langEvalConfig(vs)
	return r.interpolate(func(root ast.Node) (interface{}, error) {
		// We detect the variables again and check if the value of any
		// of the variables is the computed value. If it is, then we
		// treat this entire value as computed.
		//
		// We have to do this here before the `lang.Eval` because
		// if any of the variables it depends on are computed, then
		// the interpolation can fail at runtime for other reasons. Example:
		// `${count.index+1}`: in a world where `count.index` is computed,
		// this would fail a type check since the computed placeholder is
		// a string, but realistically the whole value is just computed.
		vars, err := DetectVariables(root)
		if err != nil {
			return "", err
		}
		for _, v := range vars {
			varVal, ok := vs[v.FullKey()]
			if ok && varVal.Value == UnknownVariableValue {
				return UnknownVariableValue, nil
			}
		}

		// None of the variables we need are computed, meaning we should
		// be able to properly evaluate.
		result, err := hil.Eval(root, config)
		if err != nil {
			return "", err
		}

		return result.Value, nil
	})
}

// Merge merges another RawConfig into this one (overriding any conflicting
// values in this config) and returns a new config. The original config
// is not modified.
func (r *RawConfig) Merge(other *RawConfig) *RawConfig {
	r.lock.Lock()
	defer r.lock.Unlock()

	// Merge the raw configurations
	raw := make(map[string]interface{})
	for k, v := range r.Raw {
		raw[k] = v
	}
	for k, v := range other.Raw {
		raw[k] = v
	}

	// Create the result
	result, err := NewRawConfig(raw)
	if err != nil {
		panic(err)
	}

	// Merge the interpolated results
	result.config = make(map[string]interface{})
	for k, v := range r.config {
		result.config[k] = v
	}
	for k, v := range other.config {
		result.config[k] = v
	}

	// Build the unknown keys
	unknownKeys := make(map[string]struct{})
	for _, k := range r.unknownKeys {
		unknownKeys[k] = struct{}{}
	}
	for _, k := range other.unknownKeys {
		unknownKeys[k] = struct{}{}
	}

	result.unknownKeys = make([]string, 0, len(unknownKeys))
	for k, _ := range unknownKeys {
		result.unknownKeys = append(result.unknownKeys, k)
	}

	return result
}

func (r *RawConfig) init() error {
	r.lock.Lock()
	defer r.lock.Unlock()

	r.config = r.Raw
	r.Interpolations = nil
	r.Variables = nil

	fn := func(node ast.Node) (interface{}, error) {
		r.Interpolations = append(r.Interpolations, node)
		vars, err := DetectVariables(node)
		if err != nil {
			return "", err
		}

		for _, v := range vars {
			if r.Variables == nil {
				r.Variables = make(map[string]InterpolatedVariable)
			}

			r.Variables[v.FullKey()] = v
		}

		return "", nil
	}

	walker := &interpolationWalker{F: fn}
	if err := reflectwalk.Walk(r.Raw, walker); err != nil {
		return err
	}

	return nil
}

func (r *RawConfig) interpolate(fn interpolationWalkerFunc) error {
	config, err := copystructure.Copy(r.Raw)
	if err != nil {
		return err
	}
	r.config = config.(map[string]interface{})

	w := &interpolationWalker{F: fn, Replace: true}
	err = reflectwalk.Walk(r.config, w)
	if err != nil {
		return err
	}

	r.unknownKeys = w.unknownKeys
	return nil
}

func (r *RawConfig) merge(r2 *RawConfig) *RawConfig {
	rawRaw, err := copystructure.Copy(r.Raw)
	if err != nil {
		panic(err)
	}

	raw := rawRaw.(map[string]interface{})
	for k, v := range r2.Raw {
		raw[k] = v
	}

	result, err := NewRawConfig(raw)
	if err != nil {
		panic(err)
	}

	return result
}

// UnknownKeys returns the keys of the configuration that are unknown
// because they had interpolated variables that must be computed.
func (r *RawConfig) UnknownKeys() []string {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.unknownKeys
}

// See GobEncode
func (r *RawConfig) GobDecode(b []byte) error {
	var data gobRawConfig
	err := gob.NewDecoder(bytes.NewReader(b)).Decode(&data)
	if err != nil {
		return err
	}

	r.Key = data.Key
	r.Raw = data.Raw

	return r.init()
}

// GobEncode is a custom Gob encoder to use so that we only include the
// raw configuration. Interpolated variables and such are lost and the
// tree of interpolated variables is recomputed on decode, since it is
// referentially transparent.
func (r *RawConfig) GobEncode() ([]byte, error) {
	r.lock.Lock()
	defer r.lock.Unlock()

	data := gobRawConfig{
		Key: r.Key,
		Raw: r.Raw,
	}

	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(data); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

type gobRawConfig struct {
	Key string
	Raw map[string]interface{}
}

// langEvalConfig returns the evaluation configuration we use to execute.
func langEvalConfig(vs map[string]ast.Variable) *hil.EvalConfig {
	funcMap := make(map[string]ast.Function)
	for k, v := range Funcs() {
		funcMap[k] = v
	}
	funcMap["lookup"] = interpolationFuncLookup(vs)
	funcMap["keys"] = interpolationFuncKeys(vs)
	funcMap["values"] = interpolationFuncValues(vs)

	return &hil.EvalConfig{
		GlobalScope: &ast.BasicScope{
			VarMap:  vs,
			FuncMap: funcMap,
		},
	}
}
<commit_msg>config: RawConfig merge should only set unknown keys non-nil if non-empty<commit_after>package config

import (
	"bytes"
	"encoding/gob"
	"sync"

	"github.com/hashicorp/hil"
	"github.com/hashicorp/hil/ast"
	"github.com/mitchellh/copystructure"
	"github.com/mitchellh/reflectwalk"
)

// UnknownVariableValue is a sentinel value that can be used
// to denote that the value of a variable is unknown at this time.
// RawConfig uses this information to build up data about
// unknown keys.
const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"

// RawConfig is a structure that holds a piece of configuration
// where te overall structure is unknown since it will be used
// to configure a plugin or some other similar external component.
//
// RawConfigs can be interpolated with variables that come from
// other resources, user variables, etc.
//
// RawConfig supports a query-like interface to request
// information from deep within the structure.
type RawConfig struct {
	Key            string
	Raw            map[string]interface{}
	Interpolations []ast.Node
	Variables      map[string]InterpolatedVariable

	lock        sync.Mutex
	config      map[string]interface{}
	unknownKeys []string
}

// NewRawConfig creates a new RawConfig structure and populates the
// publicly readable struct fields.
func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
	result := &RawConfig{Raw: raw}
	if err := result.init(); err != nil {
		return nil, err
	}

	return result, nil
}

// RawMap returns a copy of the RawConfig.Raw map.
func (r *RawConfig) RawMap() map[string]interface{} {
	r.lock.Lock()
	defer r.lock.Unlock()

	m := make(map[string]interface{})
	for k, v := range r.Raw {
		m[k] = v
	}
	return m
}

// Copy returns a copy of this RawConfig, uninterpolated.
func (r *RawConfig) Copy() *RawConfig {
	if r == nil {
		return nil
	}

	r.lock.Lock()
	defer r.lock.Unlock()

	newRaw := make(map[string]interface{})
	for k, v := range r.Raw {
		newRaw[k] = v
	}

	result, err := NewRawConfig(newRaw)
	if err != nil {
		panic("copy failed: " + err.Error())
	}

	result.Key = r.Key
	return result
}

// Value returns the value of the configuration if this configuration
// has a Key set. If this does not have a Key set, nil will be returned.
func (r *RawConfig) Value() interface{} {
	if c := r.Config(); c != nil {
		if v, ok := c[r.Key]; ok {
			return v
		}
	}

	r.lock.Lock()
	defer r.lock.Unlock()
	return r.Raw[r.Key]
}

// Config returns the entire configuration with the variables
// interpolated from any call to Interpolate.
//
// If any interpolated variables are unknown (value set to
// UnknownVariableValue), the first non-container (map, slice, etc.) element
// will be removed from the config. The keys of unknown variables
// can be found using the UnknownKeys function.
//
// By pruning out unknown keys from the configuration, the raw
// structure will always successfully decode into its ultimate
// structure using something like mapstructure.
func (r *RawConfig) Config() map[string]interface{} {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.config
}

// Interpolate uses the given mapping of variable values and uses
// those as the values to replace any variables in this raw
// configuration.
//
// Any prior calls to Interpolate are replaced with this one.
//
// If a variable key is missing, this will panic.
func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
	r.lock.Lock()
	defer r.lock.Unlock()

	config := langEvalConfig(vs)
	return r.interpolate(func(root ast.Node) (interface{}, error) {
		// We detect the variables again and check if the value of any
		// of the variables is the computed value. If it is, then we
		// treat this entire value as computed.
		//
		// We have to do this here before the `lang.Eval` because
		// if any of the variables it depends on are computed, then
		// the interpolation can fail at runtime for other reasons. Example:
		// `${count.index+1}`: in a world where `count.index` is computed,
		// this would fail a type check since the computed placeholder is
		// a string, but realistically the whole value is just computed.
		vars, err := DetectVariables(root)
		if err != nil {
			return "", err
		}
		for _, v := range vars {
			varVal, ok := vs[v.FullKey()]
			if ok && varVal.Value == UnknownVariableValue {
				return UnknownVariableValue, nil
			}
		}

		// None of the variables we need are computed, meaning we should
		// be able to properly evaluate.
		result, err := hil.Eval(root, config)
		if err != nil {
			return "", err
		}

		return result.Value, nil
	})
}

// Merge merges another RawConfig into this one (overriding any conflicting
// values in this config) and returns a new config. The original config
// is not modified.
func (r *RawConfig) Merge(other *RawConfig) *RawConfig {
	r.lock.Lock()
	defer r.lock.Unlock()

	// Merge the raw configurations
	raw := make(map[string]interface{})
	for k, v := range r.Raw {
		raw[k] = v
	}
	for k, v := range other.Raw {
		raw[k] = v
	}

	// Create the result
	result, err := NewRawConfig(raw)
	if err != nil {
		panic(err)
	}

	// Merge the interpolated results
	result.config = make(map[string]interface{})
	for k, v := range r.config {
		result.config[k] = v
	}
	for k, v := range other.config {
		result.config[k] = v
	}

	// Build the unknown keys
	if len(r.unknownKeys) > 0 || len(other.unknownKeys) > 0 {
		unknownKeys := make(map[string]struct{})
		for _, k := range r.unknownKeys {
			unknownKeys[k] = struct{}{}
		}
		for _, k := range other.unknownKeys {
			unknownKeys[k] = struct{}{}
		}

		result.unknownKeys = make([]string, 0, len(unknownKeys))
		for k, _ := range unknownKeys {
			result.unknownKeys = append(result.unknownKeys, k)
		}
	}

	return result
}

func (r *RawConfig) init() error {
	r.lock.Lock()
	defer r.lock.Unlock()

	r.config = r.Raw
	r.Interpolations = nil
	r.Variables = nil

	fn := func(node ast.Node) (interface{}, error) {
		r.Interpolations = append(r.Interpolations, node)
		vars, err := DetectVariables(node)
		if err != nil {
			return "", err
		}

		for _, v := range vars {
			if r.Variables == nil {
				r.Variables = make(map[string]InterpolatedVariable)
			}

			r.Variables[v.FullKey()] = v
		}

		return "", nil
	}

	walker := &interpolationWalker{F: fn}
	if err := reflectwalk.Walk(r.Raw, walker); err != nil {
		return err
	}

	return nil
}

func (r *RawConfig) interpolate(fn interpolationWalkerFunc) error {
	config, err := copystructure.Copy(r.Raw)
	if err != nil {
		return err
	}
	r.config = config.(map[string]interface{})

	w := &interpolationWalker{F: fn, Replace: true}
	err = reflectwalk.Walk(r.config, w)
	if err != nil {
		return err
	}

	r.unknownKeys = w.unknownKeys
	return nil
}

func (r *RawConfig) merge(r2 *RawConfig) *RawConfig {
	rawRaw, err := copystructure.Copy(r.Raw)
	if err != nil {
		panic(err)
	}

	raw := rawRaw.(map[string]interface{})
	for k, v := range r2.Raw {
		raw[k] = v
	}

	result, err := NewRawConfig(raw)
	if err != nil {
		panic(err)
	}

	return result
}

// UnknownKeys returns the keys of the configuration that are unknown
// because they had interpolated variables that must be computed.
func (r *RawConfig) UnknownKeys() []string {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.unknownKeys
}

// See GobEncode
func (r *RawConfig) GobDecode(b []byte) error {
	var data gobRawConfig
	err := gob.NewDecoder(bytes.NewReader(b)).Decode(&data)
	if err != nil {
		return err
	}

	r.Key = data.Key
	r.Raw = data.Raw

	return r.init()
}

// GobEncode is a custom Gob encoder to use so that we only include the
// raw configuration. Interpolated variables and such are lost and the
// tree of interpolated variables is recomputed on decode, since it is
// referentially transparent.
func (r *RawConfig) GobEncode() ([]byte, error) {
	r.lock.Lock()
	defer r.lock.Unlock()

	data := gobRawConfig{
		Key: r.Key,
		Raw: r.Raw,
	}

	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(data); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

type gobRawConfig struct {
	Key string
	Raw map[string]interface{}
}

// langEvalConfig returns the evaluation configuration we use to execute.
func langEvalConfig(vs map[string]ast.Variable) *hil.EvalConfig {
	funcMap := make(map[string]ast.Function)
	for k, v := range Funcs() {
		funcMap[k] = v
	}
	funcMap["lookup"] = interpolationFuncLookup(vs)
	funcMap["keys"] = interpolationFuncKeys(vs)
	funcMap["values"] = interpolationFuncValues(vs)

	return &hil.EvalConfig{
		GlobalScope: &ast.BasicScope{
			VarMap:  vs,
			FuncMap: funcMap,
		},
	}
}
<|endoftext|>


<commit_before>package connectivity

import (
	"bufio"
	"log"
	"net/http"
	"sort"
	"strconv"
	"testing"
	"time"
)

// download test data from internet
const (
	tiny   string = "http://algs4.cs.princeton.edu/15uf/tinyUF.txt"
	medium string = "http://algs4.cs.princeton.edu/15uf/mediumUF.txt"
	// huge   string = "http://algs4.cs.princeton.edu/15uf/largeUF.txt"
)

func loadTestDataFromWeb() []TestData {
	cl := &http.Client{}
	tr, err := cl.Get(tiny)
	if err != nil {
		log.Fatalln(err)
	}
	mr, err := cl.Get(medium)
	if err != nil {
		log.Fatalln(err)
	}
	// hr, err := cl.Get(huge)
	// if err != nil {
	// 	log.Fatalln(err)
	// }

	c := make(chan TestData)
	// go func() { c <- parse(hr) }()
	go func() { c <- parse(mr) }()
	go func() { c <- parse(tr) }()

	var results []TestData
	for i := 0; i < 2; /*3*/ i++ {
		result := <-c
		results = append(results, result)
	}
	return results
}

func parse(r *http.Response) (result TestData) {
	defer r.Body.Close()

	s := bufio.NewScanner(r.Body)
	s.Split(bufio.ScanWords)
	var pairs []Pair
	s.Scan()
	g, err := strconv.Atoi(s.Text())
	if err != nil {
		log.Panicf("first generator parse error %v", g, err)
	}
	for s.Scan() {
		var pair Pair
		pair.Left, err = strconv.Atoi(s.Text())
		if err != nil {
			log.Fatalf("parse left %v failed", pair.Left, err)
		}
		s.Scan()
		pair.Right, err = strconv.Atoi(s.Text())
		if err != nil {
			log.Fatalf("parse right %v failed", pair.Right, err)
		}
		pairs = append(pairs, pair)
	}

	result.Generator = g
	result.Pairs = pairs
	return result
}

type Pair struct {
	Left  int
	Right int
}

type TestData struct {
	Generator int
	Pairs     []Pair
}

func TestJustTest(t *testing.T) {
	loadStart := time.Now()
	n := loadTestDataFromWeb()
	log.Printf("loading used %v", time.Since(loadStart))
	for _, content := range n {
		log.Printf("Generator %v has %v pairs", content.Generator, len(content.Pairs))
		algoStart := time.Now()
		test := NewWeightedCompression(content.Generator)
		for idx, p := range content.Pairs {
			// log.Printf("%vth pair: %v and %v", idx, p.Left, p.Right)
			test.Union(p.Left, p.Right)
			if !test.Find(p.Left, p.Right) {
				t.Errorf("%v and %v are expected to be in the same component, this is the %vth union operation", p.Left, p.Right, idx)
			}
		}
		log.Printf("Weighted Compressed UnionFind used %v", time.Since(algoStart))
	}
}

// test set is a struct of set/bag of items, plus
// the test subject -> 2 items
// and expected output -> true or false
type TestSet struct {
	Exp      bool
	SubjectA int
	SubjectB int
	Set      Component
}

// prepare test sets
func getTestSets() *[]TestSet {
	return &[]TestSet{
		{
			Exp:      true,
			SubjectA: 2,
			SubjectB: 3,
			Set:      []int{2, 3, 6, 7},
		},
		{
			Exp:      true,
			SubjectA: 1,
			SubjectB: 4,
			Set:      []int{1, 4, 5},
		},
		{
			Exp:      false,
			SubjectA: 2,
			SubjectB: 9,
			Set:      []int{1, 2, 3, 4, 5, 7},
		},
	}
}

func TestFindQueryInSet(t *testing.T) {
	testSets := getTestSets()
	for _, test := range *testSets {
		exp := test.Exp
		inputA := test.SubjectA
		inputB := test.SubjectB
		result := test.Set.FindQueryInSingleSetNaive(inputA, inputB)
		if result != exp {
			t.Errorf("expected %q, got %q", exp, result)
		}
	}
}

// we have multiple components (sets)
// FindQuery is expected to Find if the 2 input items are
// in the same component.
// We need a struct for Components just like our previous TestSet
type TestConnectivity struct {
	Expected bool
	A        int
	B        int
	Components
}

func getTestComponents() []Component {
	return []Component{
		Component{2, 3, 6, 7}, Component{1, 4}, Component{5, 8, 9},
	}
}

func getTestSuits() *[]TestConnectivity {
	return &[]TestConnectivity{
		{
			Expected:   true,
			A:          2,
			B:          3,
			Components: getTestComponents(),
		},
		{
			Expected:   true,
			A:          1,
			B:          4,
			Components: getTestComponents(),
		},
		{
			Expected:   false,
			A:          2,
			B:          9,
			Components: getTestComponents(),
		},
	}
}

// test findquery in labyrinth
func TestFindQuery(t *testing.T) {
	testSuits := getTestSuits()
	for _, test := range *testSuits {
		exp := test.Expected
		a := test.A
		b := test.B
		result := test.Components.FindQuery(a, b)
		if result != exp {
			t.Errorf("expected %q, got %q", exp, result)
		}
	}
}

// helper func for checking 2 components
// components sorted to deliver the false negative result
// as soon as possible
func checkComponent(a, b Component) bool {
	if a == nil && b == nil {
		return true
	}
	if len(a) == len(b) {
		sort.Ints(a)
		sort.Ints(b)
		index := 0
		for index != len(a) {
			if a[index] != b[index] {
				return false
			}
			index++
		}
		return true
	}
	return false
}

// test helper func queryComponent
func TestQueryComponent(t *testing.T) {
	c := Components(getTestComponents())

	if _, got := c.queryComponent(1); !checkComponent(got, c[1]) {
		t.Errorf("expected component %v, got %v", c[1], got)
	}
	if _, got := c.queryComponent(2); !checkComponent(got, c[0]) {
		t.Errorf("expected component %v, got %v", c[0], got)
	}
	if _, got := c.queryComponent(5); !checkComponent(got, c[2]) {
		t.Errorf("expected component %v, got %v", c[2], got)
	}
	// not found digit should return nil instead of empty set, because it would
	// mess with FindQuery
	if _, got := c.queryComponent(0); !checkComponent(got, nil) {
		t.Errorf("expected component %v, got %v", nil, got)
	}
}

// test constructor
func TestConstructorNewConnectivity(t *testing.T) {
	test := NewConnectivity(10)
	expected := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	index := 0
	for index != len(test.elements) {
		if expected[index] != test.elements[index] {
			t.Errorf("expected %v, got %v", expected[index], test.elements[index])
		}
		index++
	}
}

// test union
// todo: check if the Union skips cases where two numbers are already connected
func TestUnion(t *testing.T) {
	components := Components(getTestComponents())
	components.Union(1, 5)
	if len(components) != 2 {
		t.Errorf("expected reduced component of length %v, got %v", 2, len(components))
	}

	for _, c := range components {
		if len(c) != 4 {
			if b := checkComponent(c, []int{1, 4, 5, 8, 9}); !b {
				t.Errorf("expected matched component %q, got %q", []int{1, 4, 5, 8, 9}, c)
			}
		}
	}
}
<commit_msg>change test to get all 3 url content with a timeout of 1 second<commit_after>package connectivity

import (
	"bufio"
	"log"
	"net/http"
	"sort"
	"strconv"
	"testing"
	"time"
)

// download test data from internet
const (
	tiny   string = "http://algs4.cs.princeton.edu/15uf/tinyUF.txt"
	medium string = "http://algs4.cs.princeton.edu/15uf/mediumUF.txt"
	huge   string = "http://algs4.cs.princeton.edu/15uf/largeUF.txt"
)

func loadTestDataFromWeb() []TestData {

	c := make(chan TestData)
	go func() { c <- parse(tiny) }()
	go func() { c <- parse(medium) }()
	go func() { c <- parse(huge) }()

	var results []TestData
	timeout := time.After(1 * time.Second)
	for i := 0; i < 3; i++ {
		select {
		case result := <-c:
			results = append(results, result)
		case <-timeout:
			log.Println("timed out fetching data")
			return results
		}

	}
	return results
}

func parse(url string) (result TestData) {

	cl := &http.Client{}
	r, err := cl.Get(url)
	if err != nil {
		log.Fatalln(err)
	}

	defer r.Body.Close()

	s := bufio.NewScanner(r.Body)
	s.Split(bufio.ScanWords)
	var pairs []Pair
	s.Scan()
	g, err := strconv.Atoi(s.Text())
	if err != nil {
		log.Panicf("first generator parse error %v", g, err)
	}
	for s.Scan() {
		var pair Pair
		pair.Left, err = strconv.Atoi(s.Text())
		if err != nil {
			log.Fatalf("parse left %v failed", pair.Left, err)
		}
		s.Scan()
		pair.Right, err = strconv.Atoi(s.Text())
		if err != nil {
			log.Fatalf("parse right %v failed", pair.Right, err)
		}
		pairs = append(pairs, pair)
	}

	result.Generator = g
	result.Pairs = pairs
	return result
}

type Pair struct {
	Left  int
	Right int
}

type TestData struct {
	Generator int
	Pairs     []Pair
}

func TestJustTest(t *testing.T) {
	loadStart := time.Now()
	n := loadTestDataFromWeb()
	log.Printf("loading used %v", time.Since(loadStart))
	for _, content := range n {
		log.Printf("Generator %v has %v pairs", content.Generator, len(content.Pairs))
		algoStart := time.Now()
		test := NewWeightedCompression(content.Generator)
		for idx, p := range content.Pairs {
			// log.Printf("%vth pair: %v and %v", idx, p.Left, p.Right)
			test.Union(p.Left, p.Right)
			if !test.Find(p.Left, p.Right) {
				t.Errorf("%v and %v are expected to be in the same component, this is the %vth union operation", p.Left, p.Right, idx)
			}
		}
		log.Printf("Weighted Compressed UnionFind used %v", time.Since(algoStart))
	}
}

// test set is a struct of set/bag of items, plus
// the test subject -> 2 items
// and expected output -> true or false
type TestSet struct {
	Exp      bool
	SubjectA int
	SubjectB int
	Set      Component
}

// prepare test sets
func getTestSets() *[]TestSet {
	return &[]TestSet{
		{
			Exp:      true,
			SubjectA: 2,
			SubjectB: 3,
			Set:      []int{2, 3, 6, 7},
		},
		{
			Exp:      true,
			SubjectA: 1,
			SubjectB: 4,
			Set:      []int{1, 4, 5},
		},
		{
			Exp:      false,
			SubjectA: 2,
			SubjectB: 9,
			Set:      []int{1, 2, 3, 4, 5, 7},
		},
	}
}

func TestFindQueryInSet(t *testing.T) {
	testSets := getTestSets()
	for _, test := range *testSets {
		exp := test.Exp
		inputA := test.SubjectA
		inputB := test.SubjectB
		result := test.Set.FindQueryInSingleSetNaive(inputA, inputB)
		if result != exp {
			t.Errorf("expected %q, got %q", exp, result)
		}
	}
}

// we have multiple components (sets)
// FindQuery is expected to Find if the 2 input items are
// in the same component.
// We need a struct for Components just like our previous TestSet
type TestConnectivity struct {
	Expected bool
	A        int
	B        int
	Components
}

func getTestComponents() []Component {
	return []Component{
		Component{2, 3, 6, 7}, Component{1, 4}, Component{5, 8, 9},
	}
}

func getTestSuits() *[]TestConnectivity {
	return &[]TestConnectivity{
		{
			Expected:   true,
			A:          2,
			B:          3,
			Components: getTestComponents(),
		},
		{
			Expected:   true,
			A:          1,
			B:          4,
			Components: getTestComponents(),
		},
		{
			Expected:   false,
			A:          2,
			B:          9,
			Components: getTestComponents(),
		},
	}
}

// test findquery in labyrinth
func TestFindQuery(t *testing.T) {
	testSuits := getTestSuits()
	for _, test := range *testSuits {
		exp := test.Expected
		a := test.A
		b := test.B
		result := test.Components.FindQuery(a, b)
		if result != exp {
			t.Errorf("expected %q, got %q", exp, result)
		}
	}
}

// helper func for checking 2 components
// components sorted to deliver the false negative result
// as soon as possible
func checkComponent(a, b Component) bool {
	if a == nil && b == nil {
		return true
	}
	if len(a) == len(b) {
		sort.Ints(a)
		sort.Ints(b)
		index := 0
		for index != len(a) {
			if a[index] != b[index] {
				return false
			}
			index++
		}
		return true
	}
	return false
}

// test helper func queryComponent
func TestQueryComponent(t *testing.T) {
	c := Components(getTestComponents())

	if _, got := c.queryComponent(1); !checkComponent(got, c[1]) {
		t.Errorf("expected component %v, got %v", c[1], got)
	}
	if _, got := c.queryComponent(2); !checkComponent(got, c[0]) {
		t.Errorf("expected component %v, got %v", c[0], got)
	}
	if _, got := c.queryComponent(5); !checkComponent(got, c[2]) {
		t.Errorf("expected component %v, got %v", c[2], got)
	}
	// not found digit should return nil instead of empty set, because it would
	// mess with FindQuery
	if _, got := c.queryComponent(0); !checkComponent(got, nil) {
		t.Errorf("expected component %v, got %v", nil, got)
	}
}

// test constructor
func TestConstructorNewConnectivity(t *testing.T) {
	test := NewConnectivity(10)
	expected := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	index := 0
	for index != len(test.elements) {
		if expected[index] != test.elements[index] {
			t.Errorf("expected %v, got %v", expected[index], test.elements[index])
		}
		index++
	}
}

// test union
// todo: check if the Union skips cases where two numbers are already connected
func TestUnion(t *testing.T) {
	components := Components(getTestComponents())
	components.Union(1, 5)
	if len(components) != 2 {
		t.Errorf("expected reduced component of length %v, got %v", 2, len(components))
	}

	for _, c := range components {
		if len(c) != 4 {
			if b := checkComponent(c, []int{1, 4, 5, 8, 9}); !b {
				t.Errorf("expected matched component %q, got %q", []int{1, 4, 5, 8, 9}, c)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 aaharu All rights reserved.
// This source code is licensed under the BSD-style license found in
// the LICENSE file in the root directory of this source tree.

package codegen

import (
	"bytes"
	"fmt"
	"go/format"
	"strings"

	"github.com/aaharu/schemarshal/utils"
	"github.com/aaharu/schemarshal/version"
)

var enumList = map[string][]interface{}{} // FIXME

// Generator of Go source code from JSON Schema
type Generator struct {
	name    string // package nage
	command string
	imports []*importSpec
	decls   []*typeSpec
}

// NewGenerator create Generator struct
func NewGenerator(packageName string, command string) *Generator {
	return &Generator{
		name:    packageName,
		command: command,
	}
}

// AddImport add an import statement
func (g *Generator) AddImport(path string, name string) {
	if g.imports == nil {
		g.imports = []*importSpec{}
	}
	g.imports = append(g.imports, &importSpec{
		name: name,
		path: path,
	})
}

// AddType add a type statement
func (g *Generator) AddType(name string, jsonType *JSONType) {
	if g.decls == nil {
		g.decls = []*typeSpec{}
	}
	g.decls = append(g.decls, &typeSpec{
		name:     name,
		jsontype: jsonType,
	})
}

// Generate gofmt-ed Go source code
func (g *Generator) Generate() ([]byte, error) {
	var buf bytes.Buffer

	buf.WriteString(fmt.Sprintf("// generated by %s `%s`\n", version.String(), g.command))
	buf.WriteString("\n")
	buf.WriteString(fmt.Sprintf("package %s\n\n", g.name))

	if len(g.imports) > 1 {
		buf.WriteString(fmt.Sprintf("import (\n"))
		for i := range g.imports {
			buf.WriteString(fmt.Sprintf("%s %s\n", g.imports[i].name, g.imports[i].path))
		}
		buf.WriteString(fmt.Sprintf(")\n\n"))
	} else if len(g.imports) == 1 {
		buf.WriteString(fmt.Sprintf("import %s %s\n\n", g.imports[0].name, g.imports[0].path))
	}

	if g.decls != nil {
		for i := range g.decls {
			buf.WriteString("type " + g.decls[i].name + " ")
			buf.Write(g.decls[i].jsontype.generate())
			buf.WriteString("\n")
		}
	}

	if len(enumList) > 0 {
		buf.WriteString("\n")
		for typeName, enum := range enumList {
			enumName := typeName + "Enum"
			buf.WriteString("type " + enumName + " int\n")
			buf.WriteString("const (\n")
			for i := range enum {
				if i == 0 {
					buf.WriteString(enumName + utils.UpperCamelCase(fmt.Sprintf("%v", enum[0])) + " " + enumName + " = iota\n")
				} else {
					buf.WriteString(enumName + utils.UpperCamelCase(fmt.Sprintf("%v", enum[i])) + "\n")
				}
			}
			buf.WriteString(")\n")
			buf.WriteString("func (enum " + enumName + ") MarshalJSON() ([]byte, error) {\n")
			buf.WriteString("var var" + typeName + " = []interface{}{")
			for i := range enum {
				switch v := enum[i].(type) {
				case string:
					buf.WriteString(`"`)
					buf.WriteString(strings.Replace(v, `"`, `\"`, -1))
					buf.WriteString(`"`)
				default:
					buf.WriteString(fmt.Sprintf("%v", v))
				}
				buf.WriteString(",")
			}
			buf.WriteString("}\n")
			buf.WriteString("switch v:= var" + typeName + "[enum].(type) {\n")
			buf.WriteString("case string:\n")
			buf.WriteString("return []byte(fmt.Sprintf(\"\\\"%v\\\"\", strings.Replace(v, `\"`, `\\\"`, -1))), nil\n")
			buf.WriteString("default:\n")
			buf.WriteString("return []byte(fmt.Sprintf(\"%v\", v)), nil\n")
			buf.WriteString("}\n")
			buf.WriteString("}\n\n")
		}
	}

	return format.Source(buf.Bytes())
}

type importSpec struct {
	name string // ident
	path string
}

type typeSpec struct {
	name     string // type name
	jsontype *JSONType
}

type jsonFormat int

const (
	formatObject jsonFormat = iota
	formatArray
	formatString
	formatBoolean
	formatNumber
	formatInteger
	formatDatetime
)

// JSONType ...
type JSONType struct {
	format   jsonFormat
	nullable bool
	fields   []*field  // only object
	itemType *JSONType // only array
	enumType string
}

// AddField ...
func (t *JSONType) AddField(f *field) {
	if t.fields == nil {
		t.fields = []*field{}
	}
	t.fields = append(t.fields, f)
}

func (t *JSONType) generate() []byte {
	var buf bytes.Buffer
	if t.nullable {
		buf.WriteString("*")
	}
	if t.format == formatObject {
		if t.fields == nil {
			buf.WriteString("map[string]interface{}")
		} else {
			buf.WriteString("struct {\n")
			for i := range t.fields {
				buf.WriteString(t.fields[i].name)
				buf.WriteString(" ")
				buf.Write(t.fields[i].jsontype.generate())
				buf.WriteString(" ")
				buf.Write(t.fields[i].jsontag.generate())
				buf.WriteString("\n")
			}
			buf.WriteString("}")
		}
	} else if t.format == formatArray {
		buf.WriteString("[]")
		buf.Write(t.itemType.generate())
	} else if t.format == formatString {
		buf.WriteString("string")
	} else if t.format == formatBoolean {
		buf.WriteString("bool")
	} else if t.format == formatNumber {
		buf.WriteString("float64")
	} else if t.format == formatInteger {
		buf.WriteString("int")
	} else if t.format == formatDatetime {
		buf.WriteString("time.Time")
	}
	return buf.Bytes()
}

type field struct {
	name     string
	jsontype *JSONType
	jsontag  *jsonTag
}

type jsonTag struct {
	name      string
	omitEmpty bool
}

// Generate JSON tag code
func (t *jsonTag) generate() []byte {
	var buf bytes.Buffer
	buf.WriteString("`json:\"")
	buf.WriteString(t.name)
	if t.omitEmpty {
		buf.WriteString(",omitempty")
	}
	buf.WriteString("\"`")
	return buf.Bytes()
}
<commit_msg>add generated comment<commit_after>// Copyright 2017 aaharu All rights reserved.
// This source code is licensed under the BSD-style license found in
// the LICENSE file in the root directory of this source tree.

package codegen

import (
	"bytes"
	"fmt"
	"go/format"
	"strings"

	"github.com/aaharu/schemarshal/utils"
	"github.com/aaharu/schemarshal/version"
)

var enumList = map[string][]interface{}{} // FIXME

// Generator of Go source code from JSON Schema
type Generator struct {
	name    string // package nage
	command string
	imports []*importSpec
	decls   []*typeSpec
}

// NewGenerator create Generator struct
func NewGenerator(packageName string, command string) *Generator {
	return &Generator{
		name:    packageName,
		command: command,
	}
}

// AddImport add an import statement
func (g *Generator) AddImport(path string, name string) {
	if g.imports == nil {
		g.imports = []*importSpec{}
	}
	g.imports = append(g.imports, &importSpec{
		name: name,
		path: path,
	})
}

// AddType add a type statement
func (g *Generator) AddType(name string, jsonType *JSONType) {
	if g.decls == nil {
		g.decls = []*typeSpec{}
	}
	g.decls = append(g.decls, &typeSpec{
		name:     name,
		jsontype: jsonType,
	})
}

// Generate gofmt-ed Go source code
func (g *Generator) Generate() ([]byte, error) {
	var buf bytes.Buffer

	buf.WriteString(fmt.Sprintf("// generated by %s `%s`\n", version.String(), g.command))
	buf.WriteString("// DO NOT RECOMMEND EDITING THIS FILE.\n\n")
	buf.WriteString(fmt.Sprintf("package %s\n\n", g.name))

	if len(g.imports) > 1 {
		buf.WriteString("import (\n")
		for i := range g.imports {
			buf.WriteString(fmt.Sprintf("%s %s\n", g.imports[i].name, g.imports[i].path))
		}
		buf.WriteString(")\n\n")
	} else if len(g.imports) == 1 {
		buf.WriteString(fmt.Sprintf("import %s %s\n\n", g.imports[0].name, g.imports[0].path))
	}

	if g.decls != nil {
		for i := range g.decls {
			buf.WriteString("type " + g.decls[i].name + " ")
			buf.Write(g.decls[i].jsontype.generate())
			buf.WriteString("\n")
		}
	}

	if len(enumList) > 0 {
		buf.WriteString("\n")
		for typeName, enum := range enumList {
			enumName := typeName + "Enum"
			buf.WriteString("type " + enumName + " int\n")
			buf.WriteString("const (\n")
			for i := range enum {
				if i == 0 {
					buf.WriteString(enumName + utils.UpperCamelCase(fmt.Sprintf("%v", enum[0])) + " " + enumName + " = iota\n")
				} else {
					buf.WriteString(enumName + utils.UpperCamelCase(fmt.Sprintf("%v", enum[i])) + "\n")
				}
			}
			buf.WriteString(")\n")
			buf.WriteString("func (enum " + enumName + ") MarshalJSON() ([]byte, error) {\n")
			buf.WriteString("var var" + typeName + " = []interface{}{")
			for i := range enum {
				switch v := enum[i].(type) {
				case string:
					buf.WriteString(`"`)
					buf.WriteString(strings.Replace(v, `"`, `\"`, -1))
					buf.WriteString(`"`)
				default:
					buf.WriteString(fmt.Sprintf("%v", v))
				}
				buf.WriteString(",")
			}
			buf.WriteString("}\n")
			buf.WriteString("switch v:= var" + typeName + "[enum].(type) {\n")
			buf.WriteString("case string:\n")
			buf.WriteString("return []byte(fmt.Sprintf(\"\\\"%v\\\"\", strings.Replace(v, `\"`, `\\\"`, -1))), nil\n")
			buf.WriteString("default:\n")
			buf.WriteString("return []byte(fmt.Sprintf(\"%v\", v)), nil\n")
			buf.WriteString("}\n")
			buf.WriteString("}\n\n")
		}
	}

	return format.Source(buf.Bytes())
}

type importSpec struct {
	name string // ident
	path string
}

type typeSpec struct {
	name     string // type name
	jsontype *JSONType
}

type jsonFormat int

const (
	formatObject jsonFormat = iota
	formatArray
	formatString
	formatBoolean
	formatNumber
	formatInteger
	formatDatetime
)

// JSONType ...
type JSONType struct {
	format   jsonFormat
	nullable bool
	fields   []*field  // only object
	itemType *JSONType // only array
	enumType string
}

// AddField ...
func (t *JSONType) AddField(f *field) {
	if t.fields == nil {
		t.fields = []*field{}
	}
	t.fields = append(t.fields, f)
}

func (t *JSONType) generate() []byte {
	var buf bytes.Buffer
	if t.nullable {
		buf.WriteString("*")
	}
	if t.format == formatObject {
		if t.fields == nil {
			buf.WriteString("map[string]interface{}")
		} else {
			buf.WriteString("struct {\n")
			for i := range t.fields {
				buf.WriteString(t.fields[i].name)
				buf.WriteString(" ")
				buf.Write(t.fields[i].jsontype.generate())
				buf.WriteString(" ")
				buf.Write(t.fields[i].jsontag.generate())
				buf.WriteString("\n")
			}
			buf.WriteString("}")
		}
	} else if t.format == formatArray {
		buf.WriteString("[]")
		buf.Write(t.itemType.generate())
	} else if t.format == formatString {
		buf.WriteString("string")
	} else if t.format == formatBoolean {
		buf.WriteString("bool")
	} else if t.format == formatNumber {
		buf.WriteString("float64")
	} else if t.format == formatInteger {
		buf.WriteString("int")
	} else if t.format == formatDatetime {
		buf.WriteString("time.Time")
	}
	return buf.Bytes()
}

type field struct {
	name     string
	jsontype *JSONType
	jsontag  *jsonTag
}

type jsonTag struct {
	name      string
	omitEmpty bool
}

// Generate JSON tag code
func (t *jsonTag) generate() []byte {
	var buf bytes.Buffer
	buf.WriteString("`json:\"")
	buf.WriteString(t.name)
	if t.omitEmpty {
		buf.WriteString(",omitempty")
	}
	buf.WriteString("\"`")
	return buf.Bytes()
}
<|endoftext|>


<commit_before>package collector

import (
	"context"
	"fmt"
	"log"

	"github.com/digitalocean/godo"
	"github.com/prometheus/client_golang/prometheus"
)

// DropletCollector collects metrics about all droplets.
type DropletCollector struct {
	client *godo.Client

	Up           *prometheus.Desc
	CPUs         *prometheus.Desc
	Memory       *prometheus.Desc
	Disk         *prometheus.Desc
	PriceHourly  *prometheus.Desc
	PriceMonthly *prometheus.Desc
}

// NewDropletCollector returns a new DropletCollector.
func NewDropletCollector(client *godo.Client) *DropletCollector {
	labels := []string{"id", "name", "region"}

	return &DropletCollector{
		client: client,

		Up: prometheus.NewDesc(
			"digitalocean_droplet_up",
			"If 1 the droplet is up and running, 0 otherwise",
			labels, nil,
		),
		CPUs: prometheus.NewDesc(
			"digitalocean_droplet_cpus",
			"Droplet's number of CPUs",
			labels, nil,
		),
		Memory: prometheus.NewDesc(
			"digitalocean_droplet_memory_bytes",
			"Droplet's memory in bytes",
			labels, nil,
		),
		Disk: prometheus.NewDesc(
			"digitalocean_droplet_disk_bytes",
			"Droplet's disk in bytes",
			labels, nil,
		),
		PriceHourly: prometheus.NewDesc(
			"digitalocean_droplet_price_hourly",
			"Price of the Droplet billed hourly",
			labels, nil,
		),
		PriceMonthly: prometheus.NewDesc(
			"digitalocean_droplet_price_monthly",
			"Price of the Droplet billed monthly",
			labels, nil,
		),
	}
}

// Describe sends the super-set of all possible descriptors of metrics
// collected by this Collector.
func (c *DropletCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.Up
	ch <- c.CPUs
	ch <- c.Memory
	ch <- c.Disk
	ch <- c.PriceHourly
	ch <- c.PriceMonthly
}

// Collect is called by the Prometheus registry when collecting metrics.
func (c *DropletCollector) Collect(ch chan<- prometheus.Metric) {
	droplets, _, err := c.client.Droplets.List(context.TODO(), nil)
	if err != nil {
		log.Printf("Can't list droplets: %v", err)
	}

	for _, droplet := range droplets {
		labels := []string{
			fmt.Sprintf("%d", droplet.ID),
			droplet.Name,
			droplet.Region.Slug,
		}

		var active float64
		if droplet.Status == "active" {
			active = 1.0
		}
		ch <- prometheus.MustNewConstMetric(
			c.Up,
			prometheus.GaugeValue,
			active,
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.CPUs,
			prometheus.GaugeValue,
			float64(droplet.Vcpus),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.Memory,
			prometheus.GaugeValue,
			float64(droplet.Memory*1024*1024),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.Disk,
			prometheus.GaugeValue,
			float64(droplet.Disk*1000*1000*1000),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.PriceHourly,
			prometheus.GaugeValue,
			float64(droplet.Size.PriceHourly), // TODO: Find out the correct data type
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.PriceMonthly,
			prometheus.GaugeValue,
			float64(droplet.Size.PriceMonthly), // TODO: Find out the correct data type
			labels...,
		)
	}
}
<commit_msg>Add that prices are in dollars<commit_after>package collector

import (
	"context"
	"fmt"
	"log"

	"github.com/digitalocean/godo"
	"github.com/prometheus/client_golang/prometheus"
)

// DropletCollector collects metrics about all droplets.
type DropletCollector struct {
	client *godo.Client

	Up           *prometheus.Desc
	CPUs         *prometheus.Desc
	Memory       *prometheus.Desc
	Disk         *prometheus.Desc
	PriceHourly  *prometheus.Desc
	PriceMonthly *prometheus.Desc
}

// NewDropletCollector returns a new DropletCollector.
func NewDropletCollector(client *godo.Client) *DropletCollector {
	labels := []string{"id", "name", "region"}

	return &DropletCollector{
		client: client,

		Up: prometheus.NewDesc(
			"digitalocean_droplet_up",
			"If 1 the droplet is up and running, 0 otherwise",
			labels, nil,
		),
		CPUs: prometheus.NewDesc(
			"digitalocean_droplet_cpus",
			"Droplet's number of CPUs",
			labels, nil,
		),
		Memory: prometheus.NewDesc(
			"digitalocean_droplet_memory_bytes",
			"Droplet's memory in bytes",
			labels, nil,
		),
		Disk: prometheus.NewDesc(
			"digitalocean_droplet_disk_bytes",
			"Droplet's disk in bytes",
			labels, nil,
		),
		PriceHourly: prometheus.NewDesc(
			"digitalocean_droplet_price_hourly",
			"Price of the Droplet billed hourly in dollars",
			labels, nil,
		),
		PriceMonthly: prometheus.NewDesc(
			"digitalocean_droplet_price_monthly",
			"Price of the Droplet billed monthly in dollars",
			labels, nil,
		),
	}
}

// Describe sends the super-set of all possible descriptors of metrics
// collected by this Collector.
func (c *DropletCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.Up
	ch <- c.CPUs
	ch <- c.Memory
	ch <- c.Disk
	ch <- c.PriceHourly
	ch <- c.PriceMonthly
}

// Collect is called by the Prometheus registry when collecting metrics.
func (c *DropletCollector) Collect(ch chan<- prometheus.Metric) {
	droplets, _, err := c.client.Droplets.List(context.TODO(), nil)
	if err != nil {
		log.Printf("Can't list droplets: %v", err)
	}

	for _, droplet := range droplets {
		labels := []string{
			fmt.Sprintf("%d", droplet.ID),
			droplet.Name,
			droplet.Region.Slug,
		}

		var active float64
		if droplet.Status == "active" {
			active = 1.0
		}
		ch <- prometheus.MustNewConstMetric(
			c.Up,
			prometheus.GaugeValue,
			active,
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.CPUs,
			prometheus.GaugeValue,
			float64(droplet.Vcpus),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.Memory,
			prometheus.GaugeValue,
			float64(droplet.Memory*1024*1024),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.Disk,
			prometheus.GaugeValue,
			float64(droplet.Disk*1000*1000*1000),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.PriceHourly,
			prometheus.GaugeValue,
			float64(droplet.Size.PriceHourly),
			labels...,
		)
		ch <- prometheus.MustNewConstMetric(
			c.PriceMonthly,
			prometheus.GaugeValue,
			float64(droplet.Size.PriceMonthly),
			labels...,
		)
	}
}
<|endoftext|>


<commit_before>package command

import (
	"strconv"
	"strings"

	consulapi "github.com/hashicorp/consul/api"
)

type KVDeleteCommand struct {
	Meta
}

func (c *KVDeleteCommand) Help() string {
	helpText := `
Usage: consul-cli kv-delete [options] path

  Delete a given path from the K/V

Options:

` + c.ConsulHelp() +
`  --modifyindex=<ModifyIndex>	Perform a Check-and-Set delete
				(default: not set)
  --recurse			Perform a recursive delete
				(default: false)
`

	return strings.TrimSpace(helpText)
}

func (c *KVDeleteCommand) Run (args[]string) int {
	var modifyIndex string
	var doRecurse bool
	var dc string

	flags := c.Meta.FlagSet()
	flags.StringVar(&modifyIndex, "modifyindex", "", "")
	flags.StringVar(&dc, "datacenter", "", "")
	flags.BoolVar(&doRecurse, "recurse", false, "")
	flags.Usage = func() { c.UI.Output(c.Help()) }

	if err := flags.Parse(args); err != nil {
		return 1
	}

	extra := flags.Args()
	if len(extra) < 1 {
		c.UI.Error("Key path must be specified")
		c.UI.Error("")
		c.UI.Error(c.Help())
		return 1
	}

	path := extra[0]

	consul, err := c.Client()
	if err != nil {
		c.UI.Error(err.Error())
		return 1
	}
	client := consul.KV()

	writeOpts := c.WriteOptions()

	switch {
	case doRecurse:
		_, err := client.DeleteTree(path, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
	case modifyIndex != "":
		m, err := strconv.ParseUint(modifyIndex, 0, 64)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
		kv := consulapi.KVPair{
			Key:		path,
			ModifyIndex:	m,
		}

		success, _, err := client.DeleteCAS(&kv, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}

		if !success {
			return 1
		}
	default:
		_, err := client.Delete(path, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
	}

	return 0
}

func (c *KVDeleteCommand) Synopsis() string {
	return "Delete a path"
}
<commit_msg>Remove duplicate flag<commit_after>package command

import (
	"strconv"
	"strings"

	consulapi "github.com/hashicorp/consul/api"
)

type KVDeleteCommand struct {
	Meta
}

func (c *KVDeleteCommand) Help() string {
	helpText := `
Usage: consul-cli kv-delete [options] path

  Delete a given path from the K/V

Options:

` + c.ConsulHelp() +
`  --modifyindex=<ModifyIndex>	Perform a Check-and-Set delete
				(default: not set)
  --recurse			Perform a recursive delete
				(default: false)
`

	return strings.TrimSpace(helpText)
}

func (c *KVDeleteCommand) Run (args[]string) int {
	var modifyIndex string
	var doRecurse bool

	flags := c.Meta.FlagSet()
	flags.StringVar(&modifyIndex, "modifyindex", "", "")
	flags.BoolVar(&doRecurse, "recurse", false, "")
	flags.Usage = func() { c.UI.Output(c.Help()) }

	if err := flags.Parse(args); err != nil {
		return 1
	}

	extra := flags.Args()
	if len(extra) < 1 {
		c.UI.Error("Key path must be specified")
		c.UI.Error("")
		c.UI.Error(c.Help())
		return 1
	}

	path := extra[0]

	consul, err := c.Client()
	if err != nil {
		c.UI.Error(err.Error())
		return 1
	}
	client := consul.KV()

	writeOpts := c.WriteOptions()

	switch {
	case doRecurse:
		_, err := client.DeleteTree(path, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
	case modifyIndex != "":
		m, err := strconv.ParseUint(modifyIndex, 0, 64)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
		kv := consulapi.KVPair{
			Key:		path,
			ModifyIndex:	m,
		}

		success, _, err := client.DeleteCAS(&kv, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}

		if !success {
			return 1
		}
	default:
		_, err := client.Delete(path, writeOpts)
		if err != nil {
			c.UI.Error(err.Error())
			return 1
		}
	}

	return 0
}

func (c *KVDeleteCommand) Synopsis() string {
	return "Delete a path"
}
<|endoftext|>


<commit_before>package command

import (
	"strings"
	"testing"

	"github.com/mitchellh/cli"
)

func testReadCommand(tb testing.TB) (*cli.MockUi, *ReadCommand) {
	tb.Helper()

	ui := cli.NewMockUi()
	return ui, &ReadCommand{
		BaseCommand: &BaseCommand{
			UI: ui,
		},
	}
}

func TestReadCommand_Run(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		args []string
		out  string
		code int
	}{
		{
			"not_enough_args",
			[]string{},
			"Not enough arguments",
			1,
		},
		{
			"too_many_args",
			[]string{"foo", "bar"},
			"Too many arguments",
			1,
		},
		{
			"not_found",
			[]string{"nope/not/once/never"},
			"",
			2,
		},
		{
			"default",
			[]string{"secret/read/foo"},
			"foo",
			0,
		},
		{
			"field",
			[]string{
				"-field", "foo",
				"secret/read/foo",
			},
			"bar",
			0,
		},
		{
			"field_not_found",
			[]string{
				"-field", "not-a-real-field",
				"secret/read/foo",
			},
			"not present in secret",
			1,
		},
	}

	t.Run("validations", func(t *testing.T) {
		t.Parallel()

		for _, tc := range cases {
			tc := tc

			t.Run(tc.name, func(t *testing.T) {
				t.Parallel()

				client, closer := testVaultServer(t)
				defer closer()

				if _, err := client.Logical().Write("secret/read/foo", map[string]interface{}{
					"foo": "bar",
				}); err != nil {
					t.Fatal(err)
				}

				ui, cmd := testReadCommand(t)
				cmd.client = client

				code := cmd.Run(tc.args)
				if code != tc.code {
					t.Errorf("expected %d to be %d", code, tc.code)
				}

				combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
				if !strings.Contains(combined, tc.out) {
					t.Errorf("expected %q to contain %q", combined, tc.out)
				}
			})
		}
	})

	t.Run("communication_failure", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServerBad(t)
		defer closer()

		ui, cmd := testReadCommand(t)
		cmd.client = client

		code := cmd.Run([]string{
			"secret/foo",
		})
		if exp := 2; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "Error reading secret/foo: "
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("no_tabs", func(t *testing.T) {
		t.Parallel()

		_, cmd := testReadCommand(t)
		assertNoTabs(t, cmd)
	})
}
<commit_msg>Fix read test<commit_after>package command

import (
	"strings"
	"testing"

	"github.com/mitchellh/cli"
)

func testReadCommand(tb testing.TB) (*cli.MockUi, *ReadCommand) {
	tb.Helper()

	ui := cli.NewMockUi()
	return ui, &ReadCommand{
		BaseCommand: &BaseCommand{
			UI: ui,
		},
	}
}

func TestReadCommand_Run(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		args []string
		out  string
		code int
	}{
		{
			"not_enough_args",
			[]string{},
			"Not enough arguments",
			1,
		},
		{
			"proper_args",
			[]string{"foo", "bar=baz"},
			"No value found at foo\n",
			2,
		},
		{
			"not_found",
			[]string{"nope/not/once/never"},
			"",
			2,
		},
		{
			"default",
			[]string{"secret/read/foo"},
			"foo",
			0,
		},
		{
			"field",
			[]string{
				"-field", "foo",
				"secret/read/foo",
			},
			"bar",
			0,
		},
		{
			"field_not_found",
			[]string{
				"-field", "not-a-real-field",
				"secret/read/foo",
			},
			"not present in secret",
			1,
		},
	}

	t.Run("validations", func(t *testing.T) {
		t.Parallel()

		for _, tc := range cases {
			tc := tc

			t.Run(tc.name, func(t *testing.T) {
				t.Parallel()

				client, closer := testVaultServer(t)
				defer closer()

				if _, err := client.Logical().Write("secret/read/foo", map[string]interface{}{
					"foo": "bar",
				}); err != nil {
					t.Fatal(err)
				}

				ui, cmd := testReadCommand(t)
				cmd.client = client

				code := cmd.Run(tc.args)
				if code != tc.code {
					t.Errorf("expected %d to be %d", code, tc.code)
				}

				combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
				if !strings.Contains(combined, tc.out) {
					t.Errorf("%s: expected %q to contain %q", tc.name, combined, tc.out)
				}
			})
		}
	})

	t.Run("communication_failure", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServerBad(t)
		defer closer()

		ui, cmd := testReadCommand(t)
		cmd.client = client

		code := cmd.Run([]string{
			"secret/foo",
		})
		if exp := 2; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "Error reading secret/foo: "
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("no_tabs", func(t *testing.T) {
		t.Parallel()

		_, cmd := testReadCommand(t)
		assertNoTabs(t, cmd)
	})
}
<|endoftext|>


<commit_before>package command

import (
	"testing"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

func TestShow(t *testing.T) {
	ui := new(cli.MockUi)
	c := &ShowCommand{
		ContextOpts: testCtxConfig(testProvider()),
		Ui:          ui,
	}

	args := []string{
		"bad",
		"bad",
	}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestShow_noArgs(t *testing.T) {
	ui := new(cli.MockUi)
	c := &ShowCommand{
		ContextOpts: testCtxConfig(testProvider()),
		Ui:          ui,
	}

	args := []string{}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestShow_plan(t *testing.T) {
	planPath := testPlanFile(t, &terraform.Plan{
		Config: new(config.Config),
	})

	ui := new(cli.MockUi)
	c := &ShowCommand{
		ContextOpts: testCtxConfig(testProvider()),
		Ui:          ui,
	}

	args := []string{
		planPath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}

func TestShow_state(t *testing.T) {
	originalState := &terraform.State{
		Resources: map[string]*terraform.ResourceState{
			"test_instance.foo": &terraform.ResourceState{
				ID:   "bar",
				Type: "test_instance",
			},
		},
	}

	statePath := testStateFile(t, originalState)

	ui := new(cli.MockUi)
	c := &ShowCommand{
		ContextOpts: testCtxConfig(testProvider()),
		Ui:          ui,
	}

	args := []string{
		statePath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}
<commit_msg>command/show: fix tests<commit_after>package command

import (
	"testing"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

func TestShow(t *testing.T) {
	ui := new(cli.MockUi)
	c := &ShowCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{
		"bad",
		"bad",
	}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestShow_noArgs(t *testing.T) {
	ui := new(cli.MockUi)
	c := &ShowCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestShow_plan(t *testing.T) {
	planPath := testPlanFile(t, &terraform.Plan{
		Config: new(config.Config),
	})

	ui := new(cli.MockUi)
	c := &ShowCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{
		planPath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}

func TestShow_state(t *testing.T) {
	originalState := &terraform.State{
		Resources: map[string]*terraform.ResourceState{
			"test_instance.foo": &terraform.ResourceState{
				ID:   "bar",
				Type: "test_instance",
			},
		},
	}

	statePath := testStateFile(t, originalState)

	ui := new(cli.MockUi)
	c := &ShowCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{
		statePath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Hugo 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 commands

import (
	"fmt"
	"os"
	"time"

	"github.com/gohugoio/hugo/hugolib/paths"

	"github.com/gohugoio/hugo/common/hugo"
	"github.com/gohugoio/hugo/common/loggers"
	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/helpers"
	"github.com/spf13/cobra"
)

type commandsBuilder struct {
	hugoBuilderCommon

	commands []cmder
}

func newCommandsBuilder() *commandsBuilder {
	return &commandsBuilder{}
}

func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder {
	b.commands = append(b.commands, commands...)
	return b
}

func (b *commandsBuilder) addAll() *commandsBuilder {
	b.addCommands(
		b.newServerCmd(),
		newVersionCmd(),
		newEnvCmd(),
		newConfigCmd(),
		newCheckCmd(),
		newDeployCmd(),
		newConvertCmd(),
		b.newNewCmd(),
		newListCmd(),
		newImportCmd(),
		newGenCmd(),
		createReleaser(),
		b.newModCmd(),
	)

	return b
}

func (b *commandsBuilder) build() *hugoCmd {
	h := b.newHugoCmd()
	addCommands(h.getCommand(), b.commands...)
	return h
}

func addCommands(root *cobra.Command, commands ...cmder) {
	for _, command := range commands {
		cmd := command.getCommand()
		if cmd == nil {
			continue
		}
		root.AddCommand(cmd)
	}
}

type baseCmd struct {
	cmd *cobra.Command
}

var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)

// Used in tests.
type commandsBuilderGetter interface {
	getCommandsBuilder() *commandsBuilder
}
type baseBuilderCmd struct {
	*baseCmd
	*commandsBuilder
}

func (b *baseBuilderCmd) getCommandsBuilder() *commandsBuilder {
	return b.commandsBuilder
}

func (c *baseCmd) getCommand() *cobra.Command {
	return c.cmd
}

func newBaseCmd(cmd *cobra.Command) *baseCmd {
	return &baseCmd{cmd: cmd}
}

func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
	bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
	bcmd.hugoBuilderCommon.handleFlags(cmd)
	return bcmd
}

func (c *baseCmd) flagsToConfig(cfg config.Provider) {
	initializeFlags(c.cmd, cfg)
}

type hugoCmd struct {
	*baseBuilderCmd

	// Need to get the sites once built.
	c *commandeer
}

var _ cmder = (*nilCommand)(nil)

type nilCommand struct {
}

func (c *nilCommand) getCommand() *cobra.Command {
	return nil
}

func (c *nilCommand) flagsToConfig(cfg config.Provider) {

}

func (b *commandsBuilder) newHugoCmd() *hugoCmd {
	cc := &hugoCmd{}

	cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
		Use:   "hugo",
		Short: "hugo builds your site",
		Long: `hugo is the main command, used to build your Hugo site.

Hugo is a Fast and Flexible Static Site Generator
built with love by spf13 and friends in Go.

Complete documentation is available at http://gohugo.io/.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			defer cc.timeTrack(time.Now(), "Total")
			cfgInit := func(c *commandeer) error {
				if cc.buildWatch {
					c.Set("disableLiveReload", true)
				}
				return nil
			}

			c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
			if err != nil {
				return err
			}
			cc.c = c

			return c.build()
		},
	})

	cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
	cc.cmd.PersistentFlags().StringVar(&cc.cfgDir, "configDir", "config", "config dir")
	cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode")

	// Set bash-completion
	_ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions)

	cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output")
	cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output")
	cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging")
	cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)")
	cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging")

	cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")

	cc.cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)")

	// Set bash-completion
	_ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})

	cc.cmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
	cc.cmd.SilenceUsage = true

	return cc
}

type hugoBuilderCommon struct {
	source      string
	baseURL     string
	environment string

	buildWatch bool

	gc bool

	// Profile flags (for debugging of performance problems)
	cpuprofile   string
	memprofile   string
	mutexprofile string
	traceprofile string

	// TODO(bep) var vs string
	logging    bool
	verbose    bool
	verboseLog bool
	debug      bool
	quiet      bool

	cfgFile string
	cfgDir  string
	logFile string
}

func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) {
	if cc.quiet {
		return
	}
	elapsed := time.Since(start)
	fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds()))
}

func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
	if cc.cfgDir != "" {
		return paths.AbsPathify(baseDir, cc.cfgDir)
	}

	if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
		return paths.AbsPathify(baseDir, v)
	}

	return paths.AbsPathify(baseDir, "config")
}

func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
	if cc.environment != "" {
		return cc.environment
	}

	if v, found := os.LookupEnv("HUGO_ENVIRONMENT"); found {
		return v
	}

	if isServer {
		return hugo.EnvironmentDevelopment
	}

	return hugo.EnvironmentProduction
}

func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
	cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
	cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
	cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory")
	cmd.PersistentFlags().BoolP("ignoreVendor", "", false, "ignores any _vendor directory")
}

func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
	cc.handleCommonBuilderFlags(cmd)
	cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
	cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
	cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
	cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
	cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
	cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
	cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
	cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory")
	cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to")
	cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
	cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
	cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
	cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")

	cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions")
	cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics")
	cmd.Flags().BoolP("forceSyncStatic", "", false, "copy all files when static is changed.")
	cmd.Flags().BoolP("noTimes", "", false, "don't sync modification time of files")
	cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
	cmd.Flags().BoolP("i18n-warnings", "", false, "print missing translations")
	cmd.Flags().BoolP("path-warnings", "", false, "print warnings on duplicate target paths etc.")
	cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
	cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`")
	cmd.Flags().StringVarP(&cc.mutexprofile, "profile-mutex", "", "", "write Mutex profile to `file`")
	cmd.Flags().StringVarP(&cc.traceprofile, "trace", "", "", "write trace to `file` (not useful in general)")

	// Hide these for now.
	cmd.Flags().MarkHidden("profile-cpu")
	cmd.Flags().MarkHidden("profile-mem")
	cmd.Flags().MarkHidden("profile-mutex")

	cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")

	cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")

	// Set bash-completion.
	// Each flag must first be defined before using the SetAnnotation() call.
	_ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}

func checkErr(logger *loggers.Logger, err error, s ...string) {
	if err == nil {
		return
	}
	if len(s) == 0 {
		logger.CRITICAL.Println(err)
		return
	}
	for _, message := range s {
		logger.ERROR.Println(message)
	}
	logger.ERROR.Println(err)
}
<commit_msg>commands: Use HUGO_ENV if set<commit_after>// Copyright 2019 The Hugo 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 commands

import (
	"fmt"
	"os"
	"time"

	"github.com/gohugoio/hugo/hugolib/paths"

	"github.com/gohugoio/hugo/common/hugo"
	"github.com/gohugoio/hugo/common/loggers"
	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/helpers"
	"github.com/spf13/cobra"
)

type commandsBuilder struct {
	hugoBuilderCommon

	commands []cmder
}

func newCommandsBuilder() *commandsBuilder {
	return &commandsBuilder{}
}

func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder {
	b.commands = append(b.commands, commands...)
	return b
}

func (b *commandsBuilder) addAll() *commandsBuilder {
	b.addCommands(
		b.newServerCmd(),
		newVersionCmd(),
		newEnvCmd(),
		newConfigCmd(),
		newCheckCmd(),
		newDeployCmd(),
		newConvertCmd(),
		b.newNewCmd(),
		newListCmd(),
		newImportCmd(),
		newGenCmd(),
		createReleaser(),
		b.newModCmd(),
	)

	return b
}

func (b *commandsBuilder) build() *hugoCmd {
	h := b.newHugoCmd()
	addCommands(h.getCommand(), b.commands...)
	return h
}

func addCommands(root *cobra.Command, commands ...cmder) {
	for _, command := range commands {
		cmd := command.getCommand()
		if cmd == nil {
			continue
		}
		root.AddCommand(cmd)
	}
}

type baseCmd struct {
	cmd *cobra.Command
}

var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)

// Used in tests.
type commandsBuilderGetter interface {
	getCommandsBuilder() *commandsBuilder
}
type baseBuilderCmd struct {
	*baseCmd
	*commandsBuilder
}

func (b *baseBuilderCmd) getCommandsBuilder() *commandsBuilder {
	return b.commandsBuilder
}

func (c *baseCmd) getCommand() *cobra.Command {
	return c.cmd
}

func newBaseCmd(cmd *cobra.Command) *baseCmd {
	return &baseCmd{cmd: cmd}
}

func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
	bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
	bcmd.hugoBuilderCommon.handleFlags(cmd)
	return bcmd
}

func (c *baseCmd) flagsToConfig(cfg config.Provider) {
	initializeFlags(c.cmd, cfg)
}

type hugoCmd struct {
	*baseBuilderCmd

	// Need to get the sites once built.
	c *commandeer
}

var _ cmder = (*nilCommand)(nil)

type nilCommand struct {
}

func (c *nilCommand) getCommand() *cobra.Command {
	return nil
}

func (c *nilCommand) flagsToConfig(cfg config.Provider) {

}

func (b *commandsBuilder) newHugoCmd() *hugoCmd {
	cc := &hugoCmd{}

	cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
		Use:   "hugo",
		Short: "hugo builds your site",
		Long: `hugo is the main command, used to build your Hugo site.

Hugo is a Fast and Flexible Static Site Generator
built with love by spf13 and friends in Go.

Complete documentation is available at http://gohugo.io/.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			defer cc.timeTrack(time.Now(), "Total")
			cfgInit := func(c *commandeer) error {
				if cc.buildWatch {
					c.Set("disableLiveReload", true)
				}
				return nil
			}

			c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
			if err != nil {
				return err
			}
			cc.c = c

			return c.build()
		},
	})

	cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
	cc.cmd.PersistentFlags().StringVar(&cc.cfgDir, "configDir", "config", "config dir")
	cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode")

	// Set bash-completion
	_ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions)

	cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output")
	cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output")
	cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging")
	cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)")
	cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging")

	cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")

	cc.cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)")

	// Set bash-completion
	_ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})

	cc.cmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
	cc.cmd.SilenceUsage = true

	return cc
}

type hugoBuilderCommon struct {
	source      string
	baseURL     string
	environment string

	buildWatch bool

	gc bool

	// Profile flags (for debugging of performance problems)
	cpuprofile   string
	memprofile   string
	mutexprofile string
	traceprofile string

	// TODO(bep) var vs string
	logging    bool
	verbose    bool
	verboseLog bool
	debug      bool
	quiet      bool

	cfgFile string
	cfgDir  string
	logFile string
}

func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) {
	if cc.quiet {
		return
	}
	elapsed := time.Since(start)
	fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds()))
}

func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
	if cc.cfgDir != "" {
		return paths.AbsPathify(baseDir, cc.cfgDir)
	}

	if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
		return paths.AbsPathify(baseDir, v)
	}

	return paths.AbsPathify(baseDir, "config")
}

func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
	if cc.environment != "" {
		return cc.environment
	}

	if v, found := os.LookupEnv("HUGO_ENVIRONMENT"); found {
		return v
	}

	//  Used by Netlify and Forestry
	if v, found := os.LookupEnv("HUGO_ENV"); found {
		return v
	}

	if isServer {
		return hugo.EnvironmentDevelopment
	}

	return hugo.EnvironmentProduction
}

func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
	cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
	cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
	cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory")
	cmd.PersistentFlags().BoolP("ignoreVendor", "", false, "ignores any _vendor directory")
}

func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
	cc.handleCommonBuilderFlags(cmd)
	cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
	cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
	cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
	cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
	cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
	cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
	cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
	cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory")
	cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to")
	cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)")
	cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
	cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
	cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")

	cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions")
	cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics")
	cmd.Flags().BoolP("forceSyncStatic", "", false, "copy all files when static is changed.")
	cmd.Flags().BoolP("noTimes", "", false, "don't sync modification time of files")
	cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
	cmd.Flags().BoolP("i18n-warnings", "", false, "print missing translations")
	cmd.Flags().BoolP("path-warnings", "", false, "print warnings on duplicate target paths etc.")
	cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
	cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`")
	cmd.Flags().StringVarP(&cc.mutexprofile, "profile-mutex", "", "", "write Mutex profile to `file`")
	cmd.Flags().StringVarP(&cc.traceprofile, "trace", "", "", "write trace to `file` (not useful in general)")

	// Hide these for now.
	cmd.Flags().MarkHidden("profile-cpu")
	cmd.Flags().MarkHidden("profile-mem")
	cmd.Flags().MarkHidden("profile-mutex")

	cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")

	cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")

	// Set bash-completion.
	// Each flag must first be defined before using the SetAnnotation() call.
	_ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
	_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
}

func checkErr(logger *loggers.Logger, err error, s ...string) {
	if err == nil {
		return
	}
	if len(s) == 0 {
		logger.CRITICAL.Println(err)
		return
	}
	for _, message := range s {
		logger.ERROR.Println(message)
	}
	logger.ERROR.Println(err)
}
<|endoftext|>


<commit_before>package commands

import (
	"flag"
	"net"
	"time"

	"github.com/ostrost/ostent/flags"
	"github.com/ostrost/ostent/ostent"
	"github.com/ostrost/ostent/params"
	metrics "github.com/rcrowley/go-metrics"
)

type graphite struct {
	logger      *Logger
	RefreshFlag flags.Period
	ServerAddr  flags.Bind
}

func graphiteCommandLine(cli *flag.FlagSet) CommandLineHandler {
	gr := &graphite{
		logger:      NewLogger("[ostent sendto-graphite] "),
		RefreshFlag: flags.Period{Duration: 10 * time.Second}, // 10s default
		ServerAddr:  flags.NewBind(2003),
	}
	cli.Var(&gr.RefreshFlag, "graphite-refresh", "Graphite refresh interval")
	cli.Var(&gr.ServerAddr, "sendto-graphite", "Graphite server address")
	return func() (AtexitHandler, bool, error) {
		if gr.ServerAddr.Host == "" {
			return nil, false, nil
		}
		ostent.AddBackground(func(defaultPeriod flags.Period) {
			/* if gr.RefreshFlag.Duration == 0 { // if .RefreshFlag had no default
				gr.RefreshFlag = defaultPeriod
			} */
			d := params.Duration(gr.RefreshFlag.Duration)
			gc := &carbond{
				logger:     gr.logger,
				serveraddr: gr.ServerAddr.String(),
				Ticks:      params.NewTicks(&d),
			}
			ostent.Register <- gc
		})
		return nil, false, nil
	}
}

type carbond struct {
	logger       *Logger
	serveraddr   string
	conn         net.Conn
	params.Ticks // Expired, Tick methods
	failing      bool
}

func (_ *carbond) CloseChans() {} // intentionally empty
func (_ *carbond) Reload()     {} // intentionally empty

func (_ *carbond) Push(*ostent.IndexUpdate) {} // TODO?

func (cd *carbond) Tack() {
	addr, err := net.ResolveTCPAddr("tcp", cd.serveraddr)
	if err != nil {
		cd.logger.Printf("Resolve Addr %s: %s\n", cd.serveraddr, err)
		return
	}
	// go metrics.Graphite(ostent.Reg1s.Registry, 1*time.Second, "ostent", addr)
	err = metrics.GraphiteOnce(metrics.GraphiteConfig{
		DurationUnit: time.Nanosecond, // default, used(divided by thus must not be 0) with Timer metrics
		Addr:         addr,
		Registry:     ostent.Reg1s.Registry,
		Prefix:       "ostent",
	})
	if err != nil {
		if !cd.failing {
			cd.failing = true
			cd.logger.Printf("Sending: %s\n", err)
		}
	} else if cd.failing {
		cd.failing = false
		cd.logger.Printf("Recovered\n")
	}
}

func init() {
	AddCommandLine(graphiteCommandLine)
}
<commit_msg>Use splitted go-metrics graphite adaptor<commit_after>package commands

import (
	"flag"
	"net"
	"time"

	graphite "github.com/cyberdelia/go-metrics-graphite"
	"github.com/ostrost/ostent/flags"
	"github.com/ostrost/ostent/ostent"
	"github.com/ostrost/ostent/params"
)

type Graphite struct {
	Logger      *Logger
	RefreshFlag flags.Period
	ServerAddr  flags.Bind
}

func graphiteCommandLine(cli *flag.FlagSet) CommandLineHandler {
	gr := &Graphite{
		Logger:      NewLogger("[ostent sendto-graphite] "),
		RefreshFlag: flags.Period{Duration: 10 * time.Second}, // 10s default
		ServerAddr:  flags.NewBind(2003),
	}
	cli.Var(&gr.RefreshFlag, "graphite-refresh", "Graphite refresh interval")
	cli.Var(&gr.ServerAddr, "sendto-graphite", "Graphite server address")
	return func() (AtexitHandler, bool, error) {
		if gr.ServerAddr.Host == "" {
			return nil, false, nil
		}
		ostent.AddBackground(func(defaultPeriod flags.Period) {
			/* if gr.RefreshFlag.Duration == 0 { // if .RefreshFlag had no default
				gr.RefreshFlag = defaultPeriod
			} */
			d := params.Duration(gr.RefreshFlag.Duration)
			gc := &Carbond{
				Logger:     gr.Logger,
				ServerAddr: gr.ServerAddr.String(),
				Ticks:      params.NewTicks(&d),
			}
			ostent.Register <- gc
		})
		return nil, false, nil
	}
}

type Carbond struct {
	Logger       *Logger
	ServerAddr   string
	Conn         net.Conn
	params.Ticks // Expired, Tick methods
	Failing      bool
}

func (cd *Carbond) CloseChans()              {} // intentionally empty
func (cd *Carbond) Reload()                  {} // intentionally empty
func (cd *Carbond) Push(*ostent.IndexUpdate) {} // TODO?

func (cd *Carbond) Tack() {
	addr, err := net.ResolveTCPAddr("tcp", cd.ServerAddr)
	if err != nil {
		cd.Logger.Printf("Resolve Addr %s: %s\n", cd.ServerAddr, err)
		return
	}
	// go graphite.Graphite(ostent.Reg1s.Registry, 1*time.Second, "ostent", addr)
	err = graphite.GraphiteOnce(graphite.GraphiteConfig{
		DurationUnit: time.Nanosecond, // default, used(divided by thus must not be 0) with Timer metrics
		Addr:         addr,
		Registry:     ostent.Reg1s.Registry,
		Prefix:       "ostent",
	})
	if err != nil {
		if !cd.Failing {
			cd.Failing = true
			cd.Logger.Printf("Sending: %s\n", err)
		}
	} else if cd.Failing {
		cd.Failing = false
		cd.Logger.Printf("Recovered\n")
	}
}

func init() {
	AddCommandLine(graphiteCommandLine)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Hugo 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 commands

import (
	"bytes"
	"errors"
	"path/filepath"
	"strings"

	"github.com/gohugoio/hugo/parser/metadecoders"

	_errors "github.com/pkg/errors"

	"github.com/gohugoio/hugo/create"
	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugofs"
	"github.com/gohugoio/hugo/parser"
	"github.com/spf13/cobra"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/viper"
)

var _ cmder = (*newSiteCmd)(nil)

type newSiteCmd struct {
	configFormat string

	*baseCmd
}

func newNewSiteCmd() *newSiteCmd {
	ccmd := &newSiteCmd{}

	cmd := &cobra.Command{
		Use:   "site [path]",
		Short: "Create a new site (skeleton)",
		Long: `Create a new site in the provided directory.
The new site will have the correct structure, but no content or theme yet.
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
		RunE: ccmd.newSite,
	}

	cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
	cmd.Flags().Bool("force", false, "init inside non-empty directory")

	ccmd.baseCmd = newBaseCmd(cmd)

	return ccmd

}

func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
	archeTypePath := filepath.Join(basepath, "archetypes")
	dirs := []string{
		filepath.Join(basepath, "layouts"),
		filepath.Join(basepath, "content"),
		archeTypePath,
		filepath.Join(basepath, "static"),
		filepath.Join(basepath, "data"),
		filepath.Join(basepath, "themes"),
	}

	if exists, _ := helpers.Exists(basepath, fs.Source); exists {
		if isDir, _ := helpers.IsDir(basepath, fs.Source); !isDir {
			return errors.New(basepath + " already exists but not a directory")
		}

		isEmpty, _ := helpers.IsEmpty(basepath, fs.Source)

		switch {
		case !isEmpty && !force:
			return errors.New(basepath + " already exists and is not empty")

		case !isEmpty && force:
			all := append(dirs, filepath.Join(basepath, "config."+n.configFormat))
			for _, path := range all {
				if exists, _ := helpers.Exists(path, fs.Source); exists {
					return errors.New(path + " already exists")
				}
			}
		}
	}

	for _, dir := range dirs {
		if err := fs.Source.MkdirAll(dir, 0777); err != nil {
			return _errors.Wrap(err, "Failed to create dir")
		}
	}

	createConfig(fs, basepath, n.configFormat)

	// Create a default archetype file.
	helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
		strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)

	jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
	jww.FEEDBACK.Println(nextStepsText())

	return nil
}

// newSite creates a new Hugo site and initializes a structured Hugo directory.
func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
	if len(args) < 1 {
		return newUserError("path needs to be provided")
	}

	createpath, err := filepath.Abs(filepath.Clean(args[0]))
	if err != nil {
		return newUserError(err)
	}

	forceNew, _ := cmd.Flags().GetBool("force")

	return n.doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
}

func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
	in := map[string]string{
		"baseURL":      "http://example.org/",
		"title":        "My New Hugo Site",
		"languageCode": "en-us",
	}

	var buf bytes.Buffer
	err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(kind), &buf)
	if err != nil {
		return err
	}

	return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
}

func nextStepsText() string {
	var nextStepsText bytes.Buffer

	nextStepsText.WriteString(`Just a few more steps and you're ready to go:

1. Download a theme into the same-named folder.
   Choose a theme from https://themes.gohugo.io/ or
   create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
   with "hugo new `)

	nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))

	nextStepsText.WriteString(`".
3. Start the built-in live server via "hugo server".

Visit https://gohugo.io/ for quickstart guide and full documentation.`)

	return nextStepsText.String()
}
<commit_msg>commands: Add hint when dir not empty<commit_after>// Copyright 2018 The Hugo 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 commands

import (
	"bytes"
	"errors"
	"path/filepath"
	"strings"

	"github.com/gohugoio/hugo/parser/metadecoders"

	_errors "github.com/pkg/errors"

	"github.com/gohugoio/hugo/create"
	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/hugofs"
	"github.com/gohugoio/hugo/parser"
	"github.com/spf13/cobra"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/viper"
)

var _ cmder = (*newSiteCmd)(nil)

type newSiteCmd struct {
	configFormat string

	*baseCmd
}

func newNewSiteCmd() *newSiteCmd {
	ccmd := &newSiteCmd{}

	cmd := &cobra.Command{
		Use:   "site [path]",
		Short: "Create a new site (skeleton)",
		Long: `Create a new site in the provided directory.
The new site will have the correct structure, but no content or theme yet.
Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
		RunE: ccmd.newSite,
	}

	cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
	cmd.Flags().Bool("force", false, "init inside non-empty directory")

	ccmd.baseCmd = newBaseCmd(cmd)

	return ccmd

}

func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error {
	archeTypePath := filepath.Join(basepath, "archetypes")
	dirs := []string{
		filepath.Join(basepath, "layouts"),
		filepath.Join(basepath, "content"),
		archeTypePath,
		filepath.Join(basepath, "static"),
		filepath.Join(basepath, "data"),
		filepath.Join(basepath, "themes"),
	}

	if exists, _ := helpers.Exists(basepath, fs.Source); exists {
		if isDir, _ := helpers.IsDir(basepath, fs.Source); !isDir {
			return errors.New(basepath + " already exists but not a directory")
		}

		isEmpty, _ := helpers.IsEmpty(basepath, fs.Source)

		switch {
		case !isEmpty && !force:
			return errors.New(basepath + " already exists and is not empty. See --force.")

		case !isEmpty && force:
			all := append(dirs, filepath.Join(basepath, "config."+n.configFormat))
			for _, path := range all {
				if exists, _ := helpers.Exists(path, fs.Source); exists {
					return errors.New(path + " already exists")
				}
			}
		}
	}

	for _, dir := range dirs {
		if err := fs.Source.MkdirAll(dir, 0777); err != nil {
			return _errors.Wrap(err, "Failed to create dir")
		}
	}

	createConfig(fs, basepath, n.configFormat)

	// Create a default archetype file.
	helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
		strings.NewReader(create.ArchetypeTemplateTemplate), fs.Source)

	jww.FEEDBACK.Printf("Congratulations! Your new Hugo site is created in %s.\n\n", basepath)
	jww.FEEDBACK.Println(nextStepsText())

	return nil
}

// newSite creates a new Hugo site and initializes a structured Hugo directory.
func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
	if len(args) < 1 {
		return newUserError("path needs to be provided")
	}

	createpath, err := filepath.Abs(filepath.Clean(args[0]))
	if err != nil {
		return newUserError(err)
	}

	forceNew, _ := cmd.Flags().GetBool("force")

	return n.doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
}

func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
	in := map[string]string{
		"baseURL":      "http://example.org/",
		"title":        "My New Hugo Site",
		"languageCode": "en-us",
	}

	var buf bytes.Buffer
	err = parser.InterfaceToConfig(in, metadecoders.FormatFromString(kind), &buf)
	if err != nil {
		return err
	}

	return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
}

func nextStepsText() string {
	var nextStepsText bytes.Buffer

	nextStepsText.WriteString(`Just a few more steps and you're ready to go:

1. Download a theme into the same-named folder.
   Choose a theme from https://themes.gohugo.io/ or
   create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
   with "hugo new `)

	nextStepsText.WriteString(filepath.Join("<SECTIONNAME>", "<FILENAME>.<FORMAT>"))

	nextStepsText.WriteString(`".
3. Start the built-in live server via "hugo server".

Visit https://gohugo.io/ for quickstart guide and full documentation.`)

	return nextStepsText.String()
}
<|endoftext|>