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

package dns

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

// Wraps the contents of the /etc/resolv.conf.
type ClientConfig struct {
	Servers  []string // servers to use
	Search   []string // suffixes to append to local name
	Port     string   // what port to use
	Ndots    int      // number of dots in name to trigger absolute lookup
	Timeout  int      // seconds before giving up on packet
	Attempts int      // lost packets before giving up on server
}

// ClientConfigFromFile parses a resolv.conf(5) like file and returns
// a *ClientConfig.
func ClientConfigFromFile(conf string) (*ClientConfig, error) {
	file, err := os.Open(conf)
	defer file.Close()
	if err != nil {
		return nil, err
	}
	c := new(ClientConfig)
	b := bufio.NewReader(file)
	c.Servers = make([]string, 0)
	c.Search = make([]string, 0)
	c.Port = "53"
	c.Ndots = 1
	c.Timeout = 5
	c.Attempts = 2
	for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') {
		f := strings.Fields(line)
		if len(f) < 1 {
			continue
		}
		switch f[0] {
		case "nameserver": // add one name server
			if len(f) > 1 {
				// One more check: make sure server name is
				// just an IP address.  Otherwise we need DNS
				// to look it up.
				name := f[1]
				// Don't use this. net.JoinHostPort will fix this for you
				//				switch x := net.ParseIP(name); true {
				//				case x.To4() != nil:
				//					c.Servers = append(c.Servers, name)
				//				case x.To16() != nil:
				//					name = "[" + name + "]"
				c.Servers = append(c.Servers, name)
				//				}
			}

		case "domain": // set search path to just this domain
			if len(f) > 1 {
				c.Search = make([]string, 1)
				c.Search[0] = f[1]
			} else {
				c.Search = make([]string, 0)
			}

		case "search": // set search path to given servers
			c.Search = make([]string, len(f)-1)
			for i := 0; i < len(c.Search); i++ {
				c.Search[i] = f[i+1]
			}

		case "options": // magic options
			for i := 1; i < len(f); i++ {
				s := f[i]
				switch {
				case len(s) >= 6 && s[:6] == "ndots:":
					n, _ := strconv.Atoi(s[6:])
					if n < 1 {
						n = 1
					}
					c.Ndots = n
				case len(s) >= 8 && s[:8] == "timeout:":
					n, _ := strconv.Atoi(s[8:])
					if n < 1 {
						n = 1
					}
					c.Timeout = n
				case len(s) >= 8 && s[:9] == "attempts:":
					n, _ := strconv.Atoi(s[9:])
					if n < 1 {
						n = 1
					}
					c.Attempts = n
				case s == "rotate":
					/* not imp */
				}
			}
		}
	}
	return c, nil
}
<commit_msg>Documentation<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dns

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

// Wraps the contents of the /etc/resolv.conf.
type ClientConfig struct {
	Servers  []string // servers to use
	Search   []string // suffixes to append to local name
	Port     string   // what port to use
	Ndots    int      // number of dots in name to trigger absolute lookup
	Timeout  int      // seconds before giving up on packet
	Attempts int      // lost packets before giving up on server, not used in the package dns
}

// ClientConfigFromFile parses a resolv.conf(5) like file and returns
// a *ClientConfig.
func ClientConfigFromFile(conf string) (*ClientConfig, error) {
	file, err := os.Open(conf)
	defer file.Close()
	if err != nil {
		return nil, err
	}
	c := new(ClientConfig)
	b := bufio.NewReader(file)
	c.Servers = make([]string, 0)
	c.Search = make([]string, 0)
	c.Port = "53"
	c.Ndots = 1
	c.Timeout = 5
	c.Attempts = 2
	for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') {
		f := strings.Fields(line)
		if len(f) < 1 {
			continue
		}
		switch f[0] {
		case "nameserver": // add one name server
			if len(f) > 1 {
				// One more check: make sure server name is
				// just an IP address.  Otherwise we need DNS
				// to look it up.
				name := f[1]
				// Don't use this. net.JoinHostPort will fix this for you
				//				switch x := net.ParseIP(name); true {
				//				case x.To4() != nil:
				//					c.Servers = append(c.Servers, name)
				//				case x.To16() != nil:
				//					name = "[" + name + "]"
				c.Servers = append(c.Servers, name)
				//				}
			}

		case "domain": // set search path to just this domain
			if len(f) > 1 {
				c.Search = make([]string, 1)
				c.Search[0] = f[1]
			} else {
				c.Search = make([]string, 0)
			}

		case "search": // set search path to given servers
			c.Search = make([]string, len(f)-1)
			for i := 0; i < len(c.Search); i++ {
				c.Search[i] = f[i+1]
			}

		case "options": // magic options
			for i := 1; i < len(f); i++ {
				s := f[i]
				switch {
				case len(s) >= 6 && s[:6] == "ndots:":
					n, _ := strconv.Atoi(s[6:])
					if n < 1 {
						n = 1
					}
					c.Ndots = n
				case len(s) >= 8 && s[:8] == "timeout:":
					n, _ := strconv.Atoi(s[8:])
					if n < 1 {
						n = 1
					}
					c.Timeout = n
				case len(s) >= 8 && s[:9] == "attempts:":
					n, _ := strconv.Atoi(s[9:])
					if n < 1 {
						n = 1
					}
					c.Attempts = n
				case s == "rotate":
					/* not imp */
				}
			}
		}
	}
	return c, nil
}
<|endoftext|>


<commit_before>package text

import (
	"bytes"
	"math"
)

var (
	nl = []byte{'\n'}
	sp = []byte{' '}
)

const defaultPenalty = 1e5

// Wrap wraps s into a paragraph of lines of length lim, with minimal
// raggedness.
func Wrap(s string, lim int) string {
	return string(WrapBytes([]byte(s), lim))
}

// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
// raggedness.
func WrapBytes(b []byte, lim int) []byte {
	words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
	var lines [][]byte
	for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
		lines = append(lines, bytes.Join(line, sp))
	}
	return bytes.Join(lines, nl)
}

// WrapWords is the low-level line-breaking algorithm, useful if you need more
// control over the details of the text wrapping process. For most uses, either
// Wrap or WrapBytes will be sufficient and more convenient.
//
// WrapWords splits a list of words into lines with minimal "raggedness",
// treating each byte as one unit, accounting for spc units between adjacent
// words on each line, and attempting to limit lines to lim units. Raggedness
// is the total error over all lines, where error is the square of the
// difference of the length of the line and lim. Too-long lines (which only
// happen when a single word is longer than lim units) have pen penalty units
// added to the error.
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
	n := len(words)

	length := make([][]int, n)
	for i := 0; i < n; i++ {
		length[i] = make([]int, n)
		length[i][i] = len(words[i])
		for j := i + 1; j < n; j++ {
			length[i][j] = length[i][j-1] + spc + len(words[j])
		}
	}

	nbrk := make([]int, n)
	cost := make([]int, n)
	for i := range cost {
		cost[i] = math.MaxInt32
	}
	for i := n - 1; i >= 0; i-- {
		if length[i][n-1] <= lim {
			cost[i] = 0
			nbrk[i] = n
		} else {
			for j := i + 1; j < n; j++ {
				d := lim - length[i][j-1]
				c := d*d + cost[j]
				if length[i][j-1] > lim {
					c += pen // too-long lines get a worse penalty
				}
				if c < cost[i] {
					cost[i] = c
					nbrk[i] = j
				}
			}
		}
	}

	var lines [][][]byte
	i := 0
	for i < n {
		lines = append(lines, words[i:nbrk[i]])
		i = nbrk[i]
	}
	return lines
}
<commit_msg>Fix the silly file<commit_after>package text

import (
	"bytes"
	"math"
)

var (
	nl = []byte{'\n'}
	sp = []byte{' '}
)

const defaultPenalty = 1e5

// Wrap wraps s into a paragraph of lines of length lim, with minimal
// raggedness.
func Wrap(s string, lim int) string {
	return string(WrapBytes([]byte(s), lim))
}

// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
// raggedness.
func WrapBytes(b []byte, lim int) []byte {
	words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
	var lines [][]byte
	for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
		lines = append(lines, bytes.Join(line, sp))
	}
	return bytes.Join(lines, nl)
}

// WrapWords is the low-level line-breaking algorithm, useful if you need more
// control over the details of the text wrapping process. For most uses, either
// Wrap or WrapBytes will be sufficient and more convenient.
//
// WrapWords splits a list of words into lines with minimal "raggedness",
// treating each byte as one unit, accounting for spc units between adjacent
// words on each line, and attempting to limit lines to lim units. Raggedness
// is the total error over all lines, where error is the square of the
// difference of the length of the line and lim. Too-long lines (which only
// happen when a single word is longer than lim units) have pen penalty units
// added to the error.
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
	n := len(words)

	length := make([][]int, n)
	for i := 0; i < n; i++ {
		length[i] = make([]int, n)
		length[i][i] = len(words[i])
		for j := i + 1; j < n; j++ {
			length[i][j] = length[i][j-1] + spc + len(words[j])
		}
	}

	nbrk := make([]int, n)
	cost := make([]int, n)
	for i := range cost {
		cost[i] = math.MaxInt32
	}
	for i := n - 1; i >= 0; i-- {
		if length[i][n-1] <= lim {
			cost[i] = 0
			nbrk[i] = n
		} else {
			for j := i + 1; j < n; j++ {
				d := lim - length[i][j-1]
				c := d*d + cost[j]
				if length[i][j-1] > lim {
					c += pen // too-long lines get a worse penalty
				}
				if c < cost[i] {
					cost[i] = c
					nbrk[i] = j
				}
			}
		}
	}

	var lines [][][]byte
	i := 0
	for i < n {
		lines = append(lines, words[i:nbrk[i]])
		i = nbrk[i]
	}
	return lines
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"fmt"
	"sort"
	"strings"

	humanize "github.com/dustin/go-humanize"
	flags "github.com/jessevdk/go-flags"
	"github.com/mitchellh/cli"
	"github.com/nerdalize/nerd/svc"
)

//JobList command
type JobList struct {
	*command
}

//JobListFactory creates the command
func JobListFactory(ui cli.Ui) cli.CommandFactory {
	cmd := &JobList{}
	cmd.command = createCommand(ui, cmd.Execute, cmd.Description, cmd.Usage, cmd, nil, flags.None, "nerd job list")
	return func() (cli.Command, error) {
		return cmd, nil
	}
}

//Execute runs the command
func (cmd *JobList) Execute(args []string) (err error) {
	if len(args) > 0 {
		return errShowUsage(MessageNoArgumentRequired)
	}
	kopts := cmd.globalOpts.KubeOpts
	deps, err := NewDeps(cmd.Logger(), kopts)
	if err != nil {
		return renderConfigError(err, "failed to configure")
	}

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, kopts.Timeout)
	defer cancel()

	kube := svc.NewKube(deps)

	qin := &svc.ListQuotasInput{}
	qout, err := kube.ListQuotas(ctx, qin)
	if err != nil {
		return renderServiceError(err, "failed to list quotas")
	}

	in := &svc.ListJobsInput{}

	out, err := kube.ListJobs(ctx, in)
	if err != nil {
		return renderServiceError(err, "failed to list jobs")
	}

	if len(out.Items) == 0 {
		cmd.out.Infof("No job found.")
		return nil
	}

	cmd.out.Infof("All your jobs are listed below. To see the logs of a specific job, you can use: `nerd job logs <JOB-NAME>`")
	var q *svc.ListQuotaItem
	if len(qout.Items) > 0 {
		q = qout.Items[0]
		percMem := 100 * (float64(q.UseRequestMemory) / float64(q.RequestMemory))
		percVCPU := 100 * (float64(q.UseRequestCPU) / float64(q.RequestCPU))
		memrow := []string{"Memory Usage:", fmt.Sprintf("%s / %s GB", renderMemory(q.UseRequestMemory), renderMemory(q.RequestMemory)), fmt.Sprintf("(%.1f%%)", percMem)}
		vcpurow := []string{"vCPU Usage:", fmt.Sprintf("%s / %s Core(s)", renderVCPU(q.UseRequestCPU), renderVCPU(q.RequestCPU)), fmt.Sprintf("(%.1f%%)", percVCPU)}

		cmd.out.Table([]string{"", "", "", ""}, [][]string{
			memrow,
			vcpurow,
		})

		cmd.out.Info("")
	}

	sort.Slice(out.Items, func(i int, j int) bool {
		return out.Items[i].CreatedAt.After(out.Items[j].CreatedAt)
	})

	hdr := []string{
		"JOB",
		"IMAGE",
		"INPUT",
		"OUTPUT",
		"MEMORY",
		"VCPU",
		"CREATED AT",
		"PHASE",
		"DETAILS",
	}

	rows := [][]string{}
	for _, item := range out.Items {
		rows = append(rows, []string{
			item.Name,
			item.Image,
			strings.Join(item.Input, ","),
			strings.Join(item.Output, ","),
			renderMemory(item.Memory),
			renderVCPU(item.VCPU),
			humanize.Time(item.CreatedAt),
			renderItemPhase(item),
			strings.Join(renderItemDetails(item, q), ","),
		})
	}

	return cmd.out.Table(hdr, rows)
}

// Description returns long-form help text
func (cmd *JobList) Description() string { return cmd.Synopsis() }

// Synopsis returns a one-line
func (cmd *JobList) Synopsis() string { return "Return jobs that are managed by the cluster" }

// Usage shows usage
func (cmd *JobList) Usage() string { return "nerd job list [OPTIONS]" }

func renderMemory(n int64) string {
	return fmt.Sprintf("%.1f", float64(n/1024/1024/1024)/1000)
}

func renderVCPU(n int64) string {
	return fmt.Sprintf("%.1f", float64(n)/1000)
}

func renderItemDetails(item *svc.ListJobItem, quota *svc.ListQuotaItem) (details []string) {
	if item.Details.TerminatedExitCode != 0 {
		details = append(details, fmt.Sprintf("Non-zero exit code: %d", item.Details.TerminatedExitCode))
	}

	if item.Details.WaitingReason != "" {
		wreason := item.Details.WaitingReason
		if strings.Contains(wreason, "Image") {
			wreason = "Failure while pulling image"
		}

		details = append(details, wreason)
	}

	if item.Details.UnschedulableReason != "" {
		usreason := item.Details.UnschedulableReason
		if strings.Contains(usreason, "NotYetSchedulable") {
			//this is only shown when there is no quota configured
			//@TODO what if the quota is large enough but a job will never fit on a node?
			usreason = "Not enough cluster resources"
		}

		details = append(details, usreason)
	}

	if len(item.Details.FailedCreateEvents) > 0 {
		lastMsg := ""
		for _, ev := range item.Details.FailedCreateEvents {
			if strings.Contains(ev.Message, "exceeded quota") && quota != nil {
				if item.Memory > quota.RequestMemory || item.VCPU > quota.RequestCPU {
					//user has specified something that will never fit with the curren quota settings
					lastMsg = "Specified resource request exceeds maximum"
				} else if !item.Details.Scheduled {
					//we only show this event if the pod is no scheduled since events stay behind
					//after the situation was fixed in that case don't want to show it anymore
					lastMsg = "Queued for resources"
				}
			}
		}

		if lastMsg != "" {
			details = append(details, lastMsg)
		}
	}

	return details
}

func renderItemPhase(item *svc.ListJobItem) string {
	if !item.DeletedAt.IsZero() {
		return "Deleting" //in progress of deleting
	}

	if item.Details.Parallelism == 0 {
		return "Stopped"
	}

	if !item.FailedAt.IsZero() {
		return "Failed"
	}

	if !item.CompletedAt.IsZero() {
		return "Completed"
	}

	if !item.Details.Scheduled {
		return "Waiting" //waiting to be scheduled
	}

	if !item.ActiveAt.IsZero() {
		if item.Details.Phase != "" {
			if item.Details.Phase == svc.JobDetailsPhasePending {
				return "Starting" //if not "waiting" but pending, call it "starting" instead
			}

			return string(item.Details.Phase) //detailed phase is always more usefull then active
		}

		return "Active" //little to go on, but better then nothing
	}

	return "Unknown" //by default the status is unknown
}
<commit_msg>changed container creating to something a bit more user friendly<commit_after>package cmd

import (
	"context"
	"fmt"
	"sort"
	"strings"

	humanize "github.com/dustin/go-humanize"
	flags "github.com/jessevdk/go-flags"
	"github.com/mitchellh/cli"
	"github.com/nerdalize/nerd/svc"
)

//JobList command
type JobList struct {
	*command
}

//JobListFactory creates the command
func JobListFactory(ui cli.Ui) cli.CommandFactory {
	cmd := &JobList{}
	cmd.command = createCommand(ui, cmd.Execute, cmd.Description, cmd.Usage, cmd, nil, flags.None, "nerd job list")
	return func() (cli.Command, error) {
		return cmd, nil
	}
}

//Execute runs the command
func (cmd *JobList) Execute(args []string) (err error) {
	if len(args) > 0 {
		return errShowUsage(MessageNoArgumentRequired)
	}
	kopts := cmd.globalOpts.KubeOpts
	deps, err := NewDeps(cmd.Logger(), kopts)
	if err != nil {
		return renderConfigError(err, "failed to configure")
	}

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, kopts.Timeout)
	defer cancel()

	kube := svc.NewKube(deps)

	qin := &svc.ListQuotasInput{}
	qout, err := kube.ListQuotas(ctx, qin)
	if err != nil {
		return renderServiceError(err, "failed to list quotas")
	}

	in := &svc.ListJobsInput{}

	out, err := kube.ListJobs(ctx, in)
	if err != nil {
		return renderServiceError(err, "failed to list jobs")
	}

	if len(out.Items) == 0 {
		cmd.out.Infof("No job found.")
		return nil
	}

	cmd.out.Infof("All your jobs are listed below. To see the logs of a specific job, you can use: `nerd job logs <JOB-NAME>`")
	var q *svc.ListQuotaItem
	if len(qout.Items) > 0 {
		q = qout.Items[0]
		percMem := 100 * (float64(q.UseRequestMemory) / float64(q.RequestMemory))
		percVCPU := 100 * (float64(q.UseRequestCPU) / float64(q.RequestCPU))
		memrow := []string{"Memory Usage:", fmt.Sprintf("%s / %s GB", renderMemory(q.UseRequestMemory), renderMemory(q.RequestMemory)), fmt.Sprintf("(%.1f%%)", percMem)}
		vcpurow := []string{"vCPU Usage:", fmt.Sprintf("%s / %s Core(s)", renderVCPU(q.UseRequestCPU), renderVCPU(q.RequestCPU)), fmt.Sprintf("(%.1f%%)", percVCPU)}

		cmd.out.Table([]string{"", "", "", ""}, [][]string{
			memrow,
			vcpurow,
		})

		cmd.out.Info("")
	}

	sort.Slice(out.Items, func(i int, j int) bool {
		return out.Items[i].CreatedAt.After(out.Items[j].CreatedAt)
	})

	hdr := []string{
		"JOB",
		"IMAGE",
		"INPUT",
		"OUTPUT",
		"MEMORY",
		"VCPU",
		"CREATED AT",
		"PHASE",
		"DETAILS",
	}

	rows := [][]string{}
	for _, item := range out.Items {
		rows = append(rows, []string{
			item.Name,
			item.Image,
			strings.Join(item.Input, ","),
			strings.Join(item.Output, ","),
			renderMemory(item.Memory),
			renderVCPU(item.VCPU),
			humanize.Time(item.CreatedAt),
			renderItemPhase(item),
			strings.Join(renderItemDetails(item, q), ","),
		})
	}

	return cmd.out.Table(hdr, rows)
}

// Description returns long-form help text
func (cmd *JobList) Description() string { return cmd.Synopsis() }

// Synopsis returns a one-line
func (cmd *JobList) Synopsis() string { return "Return jobs that are managed by the cluster" }

// Usage shows usage
func (cmd *JobList) Usage() string { return "nerd job list [OPTIONS]" }

func renderMemory(n int64) string {
	return fmt.Sprintf("%.1f", float64(n/1024/1024/1024)/1000)
}

func renderVCPU(n int64) string {
	return fmt.Sprintf("%.1f", float64(n)/1000)
}

func renderItemDetails(item *svc.ListJobItem, quota *svc.ListQuotaItem) (details []string) {
	if item.Details.TerminatedExitCode != 0 {
		details = append(details, fmt.Sprintf("Non-zero exit code: %d", item.Details.TerminatedExitCode))
	}

	if item.Details.WaitingReason != "" {
		wreason := item.Details.WaitingReason
		if strings.Contains(wreason, "Image") {
			wreason = "Failure while pulling image"
		}

		if wreason == "ContainerCreating" {
			wreason = "Creating Container"
		}

		details = append(details, wreason)
	}

	if item.Details.UnschedulableReason != "" {
		usreason := item.Details.UnschedulableReason
		if strings.Contains(usreason, "NotYetSchedulable") {
			//this is only shown when there is no quota configured
			//@TODO what if the quota is large enough but a job will never fit on a node?
			usreason = "Not enough cluster resources"
		}

		details = append(details, usreason)
	}

	if len(item.Details.FailedCreateEvents) > 0 {
		lastMsg := ""
		for _, ev := range item.Details.FailedCreateEvents {
			if strings.Contains(ev.Message, "exceeded quota") && quota != nil {
				if item.Memory > quota.RequestMemory || item.VCPU > quota.RequestCPU {
					//user has specified something that will never fit with the curren quota settings
					lastMsg = "Specified resource request exceeds maximum"
				} else if !item.Details.Scheduled {
					//we only show this event if the pod is no scheduled since events stay behind
					//after the situation was fixed in that case don't want to show it anymore
					lastMsg = "Queued for resources"
				}
			}
		}

		if lastMsg != "" {
			details = append(details, lastMsg)
		}
	}

	return details
}

func renderItemPhase(item *svc.ListJobItem) string {
	if !item.DeletedAt.IsZero() {
		return "Deleting" //in progress of deleting
	}

	if item.Details.Parallelism == 0 {
		return "Stopped"
	}

	if !item.FailedAt.IsZero() {
		return "Failed"
	}

	if !item.CompletedAt.IsZero() {
		return "Completed"
	}

	if !item.Details.Scheduled {
		return "Waiting" //waiting to be scheduled
	}

	if !item.ActiveAt.IsZero() {
		if item.Details.Phase != "" {
			if item.Details.Phase == svc.JobDetailsPhasePending {
				return "Starting" //if not "waiting" but pending, call it "starting" instead
			}

			return string(item.Details.Phase) //detailed phase is always more usefull then active
		}

		return "Active" //little to go on, but better then nothing
	}

	return "Unknown" //by default the status is unknown
}
<|endoftext|>


<commit_before>package main

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

	"github.com/fatih/color"
	"github.com/influx6/faux/fmtwriter"
	"github.com/influx6/faux/metrics"
	"github.com/influx6/faux/metrics/sentries/stdout"
	"github.com/influx6/moz"
	"github.com/influx6/moz/ast"
	"github.com/influx6/moz/cmd/moz/templates"
	"github.com/influx6/moz/gen"
	"github.com/influx6/moz/utils"
	"github.com/minio/cli"

	_ "github.com/influx6/moz/annotations"
)

var (
	events      = metrics.New(stdout.Stdout{})
	annotations = moz.CopyAnnotationsTo(ast.NewAnnotationRegistryWith(events))
)

// Version defines the version number for the cli.
var Version = "0.1"

var helpTemplate = `NAME:
{{.Name}} - {{.Usage}}

DESCRIPTION:
{{.Description}}

USAGE:
{{.Name}} {{if .Flags}}[flags] {{end}}command{{if .Flags}}{{end}} [arguments...]

COMMANDS:
	{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
	{{end}}{{if .Flags}}
FLAGS:
	{{range .Flags}}{{.}}
	{{end}}{{end}}
VERSION:
` + Version +
	`{{ "\n"}}`

// Cmd defines a struct for defining a command.
type Cmd struct {
	*cli.App
}

// VersionAction defines the action called when seeking the Version detail.
func VersionAction(c *cli.Context) {
	fmt.Println(color.BlueString(fmt.Sprintf("moz version %s %s/%s", Version, runtime.GOOS, runtime.GOARCH)))
}

func main() {
	app := cli.NewApp()
	app.Name = "moz"
	app.Author = ""
	app.Usage = "moz {{command}}"
	app.Flags = []cli.Flag{}
	app.Description = "moz: CLI tooling for the go language generator."
	app.CustomAppHelpTemplate = helpTemplate

	app.Commands = []cli.Command{
		{
			Name:   "version",
			Action: VersionAction,
			Flags:  []cli.Flag{},
		},
		{
			Name:        "generate-file",
			Action:      generateFileCLI,
			Description: "Runs the moz parser to parse and generate code for all annotations found in the file",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f,fromFile",
					Value: "",
					Usage: "-f=./",
				},
				cli.BoolFlag{
					Name:  "fw,forceWrite",
					Usage: "-fw=true",
				},
				cli.StringFlag{
					Name:  "t,toDir",
					Value: "",
					Usage: "-t=./",
				},
			},
		},
		{
			Name:        "generate",
			Action:      generatePackageCLI,
			Description: "Runs the moz parser to parse and generate code for all annotations in the package directory",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f,fromDir",
					Value: "",
					Usage: "-f=./",
				},
				cli.BoolFlag{
					Name:  "fw,forceWrite",
					Usage: "-fw=true",
				},
				cli.StringFlag{
					Name:  "t,toDir",
					Value: "",
					Usage: "-t=./",
				},
			},
		},
		{
			Name:        "assets",
			Action:      assetsCLI,
			Description: "Generates a package to build files into go source",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "n,name",
					Value: "assets",
					Usage: "-n=assets",
				},
				cli.StringFlag{
					Name:  "e,exts",
					Value: "",
					Usage: "-e='.tml, .ball, .css'",
				},
				cli.StringFlag{
					Name:  "r,root",
					Value: "./",
					Usage: "-r=/tmp/bob",
				},
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		return nil
	}

	app.RunAndExitOnError()
}

func assetsCLI(c *cli.Context) {
	extensions := strings.Split(c.String("exts"), ",")

	pkgName := c.String("name")

	rootCMD := c.String("root")
	if rootCMD == "" {
		rootCMD = "./"
	}

	inDir := "files"
	rootDir := filepath.Join(rootCMD, pkgName)
	assetDir := filepath.Join(rootDir, inDir)

	genFile := gen.Package(
		gen.Name(pkgName),
		gen.Text("//go:generate go run generate.go"),
	)

	mainFile := gen.Block(
		gen.Commentary(
			gen.Text("+build ignore"),
		),
		gen.Text("\n"),
		gen.Package(
			gen.Name("main"),
			gen.Imports(
				gen.Import("fmt", ""),
				gen.Import("path/filepath", ""),
				gen.Import("github.com/influx6/moz/gen", ""),
				gen.Import("github.com/influx6/moz/utils", ""),
				gen.Import("github.com/influx6/faux/vfiles", ""),
				gen.Import("github.com/influx6/faux/fmtwriter", ""),
				gen.Import("github.com/influx6/faux/metrics", ""),
				gen.Import("github.com/influx6/faux/metrics/sentries/stdout", ""),
			),
			gen.Function(
				gen.Name("main"),
				gen.Constructor(),
				gen.Returns(),
				gen.Block(
					gen.SourceText(
						templates.Must("main.tml"),
						struct {
							Extensions       []string
							TargetDir        string
							Package          string
							GenerateTemplate string
						}{
							TargetDir:  inDir,
							Extensions: extensions,
							Package:    pkgName,
							GenerateTemplate: `{{range $key, $value := .Files}}
								files[{{quote $key}}] = []byte("{{$value}}")
							{{end}}`,
						},
					),
				),
			),
		),
	)

	if err := os.MkdirAll(assetDir, 0700); err != nil && !os.IsExist(err) {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory"))
		panic(err)
	}

	genDir := filepath.Join(rootDir, pkgName+".go")
	if err := utils.WriteFile(events, fmtwriter.New(genFile, true, true), genDir); err != nil {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory: generate.go"))
		panic(err)
	}

	dir := filepath.Join(rootDir, "generate.go")
	if err := utils.WriteFile(events, fmtwriter.New(mainFile, true, true), dir); err != nil {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory: generate.go"))
		panic(err)
	}
}

func generateFileCLI(c *cli.Context) {
	var err error

	forceWrite := c.Bool("forceWrite")
	fromFile := c.String("fromFile")
	if fromFile == "" {
		err = fmt.Errorf("file target not provided, use the -fromfile flag")
		events.Emit(stdout.Error(err).With("dir", fromFile).With("message", "Failed to retrieve current directory"))
		return
	}

	toDir := c.String("toDir")
	if filepath.IsAbs(toDir) {
		err = fmt.Errorf("-toDir flag can not be a absolute path but a relative path to the directory")
		events.Emit(stdout.Error(err).With("dir", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
		return
	}

	if fromFile == "" {
		fromFile, err = os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current fileectory"))
			return
		}
	}

	// If its not an absolute path then get real absolute
	if !filepath.IsAbs(fromFile) {
		pwd, err := os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current fileectory"))
			return
		}

		fromFile = filepath.Join(pwd, fromFile)
	}

	events.Emit(stdout.Info("Using FromFile: %s", fromFile).With("file", fromFile))
	events.Emit(stdout.Info("Using ToDir: %s", toDir).With("Dir", toDir))

	pkg, err := ast.ParseFileAnnotations(events, fromFile)
	if err != nil {
		events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to parse package annotations"))
		return
	}

	events.Emit(stdout.Info("Begin Annotation Execution").With("toDir", toDir).With("fromFile", fromFile))

	if err := moz.ParseWith(toDir, events, annotations, forceWrite, pkg); err != nil {
		events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to parse package declarations"))
	}

	events.Emit(stdout.Info("Finished").With("toDir", toDir).With("fromFile", fromFile))
}

func generatePackageCLI(c *cli.Context) {
	var err error

	forceWrite := c.Bool("forceWrite")
	fromDir := c.String("fromDir")
	toDir := c.String("toDir")

	if filepath.IsAbs(toDir) {
		err = fmt.Errorf("-toDir flag can not be a absolute path but a relative path to the directory")
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
		return
	}

	if fromDir == "" {
		fromDir, err = os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
			return
		}
	}

	events.Emit(stdout.Info("Using FromDir: %s", fromDir).With("dir", fromDir))
	events.Emit(stdout.Info("Using ToDir: %s", toDir).With("dir", toDir))

	pkgs, err := ast.ParseAnnotations(events, fromDir)
	if err != nil {
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to parse package annotations"))
		return
	}

	events.Emit(stdout.Info("Begin Annotation Execution").With("toDir", toDir).With("fromDir", fromDir))

	if err := moz.ParseWith(toDir, events, annotations, forceWrite, pkgs...); err != nil {
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to parse package declarations"))
	}

	events.Emit(stdout.Info("Finished").With("toDir", toDir).With("fromDir", fromDir))
}
<commit_msg>Add logger to AnnotationRegistry<commit_after>package main

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

	"github.com/fatih/color"
	"github.com/influx6/faux/fmtwriter"
	"github.com/influx6/faux/metrics"
	"github.com/influx6/faux/metrics/sentries/stdout"
	"github.com/influx6/moz"
	"github.com/influx6/moz/ast"
	"github.com/influx6/moz/cmd/moz/templates"
	"github.com/influx6/moz/gen"
	"github.com/influx6/moz/utils"
	"github.com/minio/cli"

	_ "github.com/influx6/moz/annotations"
)

var (
	events      = metrics.New(stdout.Stdout{})
	annotations = moz.CopyAnnotationsTo(ast.NewAnnotationRegistryWith(events))
)

// Version defines the version number for the cli.
var Version = "0.1"

var helpTemplate = `NAME:
{{.Name}} - {{.Usage}}

DESCRIPTION:
{{.Description}}

USAGE:
{{.Name}} {{if .Flags}}[flags] {{end}}command{{if .Flags}}{{end}} [arguments...]

COMMANDS:
	{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
	{{end}}{{if .Flags}}
FLAGS:
	{{range .Flags}}{{.}}
	{{end}}{{end}}
VERSION:
` + Version +
	`{{ "\n"}}`

// Cmd defines a struct for defining a command.
type Cmd struct {
	*cli.App
}

// VersionAction defines the action called when seeking the Version detail.
func VersionAction(c *cli.Context) {
	fmt.Println(color.BlueString(fmt.Sprintf("moz version %s %s/%s", Version, runtime.GOOS, runtime.GOARCH)))
}

func main() {
	app := cli.NewApp()
	app.Name = "moz"
	app.Author = ""
	app.Usage = "moz {{command}}"
	app.Flags = []cli.Flag{}
	app.Description = "moz: CLI tooling for the go language generator."
	app.CustomAppHelpTemplate = helpTemplate

	app.Commands = []cli.Command{
		{
			Name:   "version",
			Action: VersionAction,
			Flags:  []cli.Flag{},
		},
		{
			Name:        "generate-file",
			Action:      generateFileCLI,
			Description: "Runs the moz parser to parse and generate code for all annotations found in the file",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f,fromFile",
					Value: "",
					Usage: "-f=./",
				},
				cli.BoolFlag{
					Name:  "fw,forceWrite",
					Usage: "-fw=true",
				},
				cli.StringFlag{
					Name:  "t,toDir",
					Value: "",
					Usage: "-t=./",
				},
			},
		},
		{
			Name:        "generate",
			Action:      generatePackageCLI,
			Description: "Runs the moz parser to parse and generate code for all annotations in the package directory",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f,fromDir",
					Value: "",
					Usage: "-f=./",
				},
				cli.BoolFlag{
					Name:  "fw,forceWrite",
					Usage: "-fw=true",
				},
				cli.StringFlag{
					Name:  "t,toDir",
					Value: "",
					Usage: "-t=./",
				},
			},
		},
		{
			Name:        "assets",
			Action:      assetsCLI,
			Description: "Generates a package to build files into go source",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "n,name",
					Value: "assets",
					Usage: "-n=assets",
				},
				cli.StringFlag{
					Name:  "e,exts",
					Value: "",
					Usage: "-e='.tml, .ball, .css'",
				},
				cli.StringFlag{
					Name:  "r,root",
					Value: "./",
					Usage: "-r=/tmp/bob",
				},
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		return nil
	}

	app.RunAndExitOnError()
}

func assetsCLI(c *cli.Context) {
	extensions := strings.Split(c.String("exts"), ",")

	pkgName := c.String("name")

	rootCMD := c.String("root")
	if rootCMD == "" {
		rootCMD = "./"
	}

	inDir := "files"
	rootDir := filepath.Join(rootCMD, pkgName)
	assetDir := filepath.Join(rootDir, inDir)

	genFile := gen.Package(
		gen.Name(pkgName),
		gen.Text("//go:generate go run generate.go"),
	)

	mainFile := gen.Block(
		gen.Commentary(
			gen.Text("+build ignore"),
		),
		gen.Text("\n"),
		gen.Package(
			gen.Name("main"),
			gen.Imports(
				gen.Import("fmt", ""),
				gen.Import("path/filepath", ""),
				gen.Import("github.com/influx6/moz/gen", ""),
				gen.Import("github.com/influx6/moz/utils", ""),
				gen.Import("github.com/influx6/faux/vfiles", ""),
				gen.Import("github.com/influx6/faux/fmtwriter", ""),
				gen.Import("github.com/influx6/faux/metrics", ""),
				gen.Import("github.com/influx6/faux/metrics/sentries/stdout", ""),
			),
			gen.Function(
				gen.Name("main"),
				gen.Constructor(),
				gen.Returns(),
				gen.Block(
					gen.SourceText(
						templates.Must("main.tml"),
						struct {
							Extensions       []string
							TargetDir        string
							Package          string
							GenerateTemplate string
						}{
							TargetDir:  inDir,
							Extensions: extensions,
							Package:    pkgName,
							GenerateTemplate: `{{range $key, $value := .Files}}
								files[{{quote $key}}] = []byte("{{$value}}")
							{{end}}`,
						},
					),
				),
			),
		),
	)

	if err := os.MkdirAll(assetDir, 0700); err != nil && !os.IsExist(err) {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory"))
		panic(err)
	}

	genDir := filepath.Join(rootDir, pkgName+".go")
	if err := utils.WriteFile(events, fmtwriter.New(genFile, true, true), genDir); err != nil {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory: generate.go"))
		panic(err)
	}

	dir := filepath.Join(rootDir, "generate.go")
	if err := utils.WriteFile(events, fmtwriter.New(mainFile, true, true), dir); err != nil {
		events.Emit(stdout.Error(err).With("dir", rootCMD).
			With("targetDir", rootDir).
			With("message", "Failed to create new package directory: generate.go"))
		panic(err)
	}
}

func generateFileCLI(c *cli.Context) {
	var err error

	forceWrite := c.Bool("forceWrite")
	fromFile := c.String("fromFile")
	if fromFile == "" {
		err = fmt.Errorf("file target not provided, use the -fromfile flag")
		events.Emit(stdout.Error(err).With("dir", fromFile).With("message", "Failed to retrieve current directory"))
		return
	}

	toDir := c.String("toDir")
	if filepath.IsAbs(toDir) {
		err = fmt.Errorf("-toDir flag can not be a absolute path but a relative path to the directory")
		events.Emit(stdout.Error(err).With("dir", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
		return
	}

	if fromFile == "" {
		fromFile, err = os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current fileectory"))
			return
		}
	}

	// If its not an absolute path then get real absolute
	if !filepath.IsAbs(fromFile) {
		pwd, err := os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to retrieve current fileectory"))
			return
		}

		fromFile = filepath.Join(pwd, fromFile)
	}

	events.Emit(stdout.Info("Using FromFile: %s", fromFile).With("file", fromFile))
	events.Emit(stdout.Info("Using ToDir: %s", toDir).With("Dir", toDir))

	pkg, err := ast.ParseFileAnnotations(events, fromFile)
	if err != nil {
		events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to parse package annotations"))
		return
	}

	events.Emit(stdout.Info("Begin Annotation Execution").With("toDir", toDir).With("fromFile", fromFile))

	if err := moz.ParseWith(toDir, events, annotations, forceWrite, pkg); err != nil {
		events.Emit(stdout.Error(err).With("file", fromFile).With("toDir", toDir).With("message", "Failed to parse package declarations"))
	}

	events.Emit(stdout.Info("Finished").With("toDir", toDir).With("fromFile", fromFile))
}

func generatePackageCLI(c *cli.Context) {
	var err error

	forceWrite := c.Bool("forceWrite")
	fromDir := c.String("fromDir")
	toDir := c.String("toDir")

	if filepath.IsAbs(toDir) {
		err = fmt.Errorf("-toDir flag can not be a absolute path but a relative path to the directory")
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
		return
	}

	if fromDir == "" {
		fromDir, err = os.Getwd()
		if err != nil {
			events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to retrieve current directory"))
			return
		}
	}

	events.Emit(stdout.Info("Using FromDir: %s", fromDir).With("dir", fromDir))
	events.Emit(stdout.Info("Using ToDir: %s", toDir).With("dir", toDir))

	pkgs, err := ast.ParseAnnotations(events, fromDir)
	if err != nil {
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to parse package annotations"))
		return
	}

	events.Emit(stdout.Info("Begin Annotation Execution").With("toDir", toDir).With("fromDir", fromDir).With("Packages", len(pkgs)))

	if err := moz.ParseWith(toDir, events, annotations, forceWrite, pkgs...); err != nil {
		events.Emit(stdout.Error(err).With("dir", fromDir).With("toDir", toDir).With("message", "Failed to parse package declarations"))
	}

	events.Emit(stdout.Info("Finished").With("toDir", toDir).With("fromDir", fromDir))
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Frank Wessels <fwessels@xs4all.nl>
 *
 * 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 cmd

import (
	"github.com/s3git/s3git-go"
	"github.com/spf13/cobra"
)

// snapshotCmd represents the snapshot command
var snapshotCmd = &cobra.Command{
	Use:   "snapshot",
	Short: "Manage snapshots",
	Long: "Create, checkout and list snapshots",
}

var snapshotCreateCmd = &cobra.Command{
	Use:   "create [directory]",
	Short: "Create a snapshot",
	Long: "Create a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		if len(args) == 0 {
			er("Directory for snapshot must be specified")
		} else if message == "" {
			er("Commit message for snapshot must be specified")
		}

		_/*repo*/, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		//err = repo.SnapshotCreate()
		//if err != nil {
		//	er(err)
		//}
	},
}

var snapshotCheckoutCmd = &cobra.Command{
	Use:   "checkout [commit] [directory]",
	Short: "Checkout a snapshot",
	Long: "Checkout a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		if len(args) == 0 {
			er("Commit for snapshot must be specified")
		}

		_ /*repo*/, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		//err = repo.RemoteRemove(args[0])
		//if err != nil {
		//	er(err)
		//}
	},
}

var snapshotListCmd = &cobra.Command{
	Use:   "list [commit]",
	Short: "List a snapshot",
	Long: "List a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		_/*repo*/, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}
	},
}

var snapshotLogCmd = &cobra.Command{
	Use:   "log",
	Short: "Show commit log for snapshots",
	Long: "Show commit log for snapshots",
	Run: func(cmd *cobra.Command, args []string) {

		_/*repo*/, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(snapshotCmd)
	snapshotCmd.AddCommand(snapshotCreateCmd)
	snapshotCmd.AddCommand(snapshotCheckoutCmd)
	snapshotCmd.AddCommand(snapshotListCmd)
	snapshotCmd.AddCommand(snapshotLogCmd)

	// Add local message flags
	snapshotCreateCmd.Flags().StringVarP(&message, "message", "m", "", "Message for the commit of create snapshot")
}
<commit_msg>Command line support for snapshots<commit_after>/*
 * Copyright 2016 Frank Wessels <fwessels@xs4all.nl>
 *
 * 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 cmd

import (
	"fmt"
	"github.com/s3git/s3git-go"
	"github.com/spf13/cobra"
)

// snapshotCmd represents the snapshot command
var snapshotCmd = &cobra.Command{
	Use:   "snapshot",
	Short: "Manage snapshots",
	Long: "Create, checkout and list snapshots",
}

var snapshotCreateCmd = &cobra.Command{
	Use:   "create [directory]",
	Short: "Create a snapshot",
	Long: "Create a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		if len(args) == 0 {
			er("Directory for snapshot must be specified")
		} else if message == "" {
			er("Commit message for snapshot must be specified")
		}

		repo, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		key, nothing, err := repo.SnapshotCreate(args[0], message)
		if err != nil {
			er(err)
		}
		if nothing {
			fmt.Println("No changes to snapshot")
		} else {
			fmt.Printf("[commit %s]\n", key)
		}
	},
}

var snapshotCheckoutCmd = &cobra.Command{
	Use:   "checkout [directory] ([commit])",
	Short: "Checkout a snapshot",
	Long: "Checkout a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		// TODO: Partial checkout would be nice (eg specify path as filter)

		if len(args) == 0 {
			er("Directory for snapshot must be specified")
		}

		repo, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		var commit string
		if len(args) == 2 {
			commit = args[1]
		}

		err = repo.SnapshotCheckout(args[0], commit, hydrate)
		if err != nil {
			er(err)
		}
	},
}

var presignedUrls bool
var jsonOutput bool

var snapshotListCmd = &cobra.Command{
	Use:   "ls ([commit])",
	Short: "List a snapshot",
	Long: "List a snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		if len(args) == 0 {
			er("Commit for snapshot must be specified")
		}

		repo, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		var commit string
		if len(args) == 1 {
			commit = args[0]
		}

		// TODO: Dump result in JSON format
		err = repo.SnapshotList(commit, presignedUrls)
		if err != nil {
			er(err)
		}

	},
}

var snapshotLogCmd = &cobra.Command{
	Use:   "log",
	Short: "Show commit log for snapshots",
	Long: "Show commit log for snapshots",
	Run: func(cmd *cobra.Command, args []string) {

		_/*repo*/, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		// TODO: Implement log
	},
}

var snapshotStatusCmd = &cobra.Command{
	Use:   "status [directory] ([commit])",
	Short: "Show changes for snapshot",
	Long: "Show changes for snapshot",
	Run: func(cmd *cobra.Command, args []string) {

		if len(args) == 0 {
			er("Directory for snapshot must be specified")
		}

		repo, err := s3git.OpenRepository(".")
		if err != nil {
			er(err)
		}

		var commit string
		if len(args) == 2 {
			commit = args[1]
		}

		err = repo.SnapshotStatus(args[0], commit)
		if err != nil {
			er(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(snapshotCmd)
	snapshotCmd.AddCommand(snapshotCreateCmd)
	snapshotCmd.AddCommand(snapshotCheckoutCmd)
	snapshotCmd.AddCommand(snapshotListCmd)
	snapshotCmd.AddCommand(snapshotLogCmd)
	snapshotCmd.AddCommand(snapshotStatusCmd)

	// Local flags for create
	snapshotCreateCmd.Flags().StringVarP(&message, "message", "m", "", "Message for the commit of create snapshot")

	// Local flags for checkout
	snapshotCheckoutCmd.Flags().BoolVar(&hydrate, "hydrate", false, "Checkout in hydrated (original) format")

	// Local flags for list
	snapshotListCmd.Flags().BoolVar(&presignedUrls, "presigned", false, "Generate presigned urls for direct access from S3")
	snapshotListCmd.Flags().BoolVar(&presignedUrls, "json", false, "Output result in JSON")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"html/template"
	"log"
	"os"
	"os/exec"
	"strings"

	"github.com/thrasher-/gocryptotrader/common"
	"github.com/thrasher-/gocryptotrader/config"
)

const (
	packageTests   = "%s_test.go"
	packageTypes   = "%s_types.go"
	packageWrapper = "%s_wrapper.go"
	packageMain    = "%s.go"
	packageReadme  = "README.md"

	exchangePackageLocation = "../../exchanges/"
	exchangeLocation        = "../../exchange.go"
)

var (
	exchangeDirectory string
	exchangeTest      string
	exchangeTypes     string
	exchangeWrapper   string
	exchangeMain      string
	exchangeReadme    string
)

type exchange struct {
	Name        string
	CapitalName string
	Variable    string
	REST        bool
	WS          bool
	FIX         bool
}

func main() {
	var newExchangeName string
	var websocketSupport, restSupport, fixSupport bool

	flag.StringVar(&newExchangeName, "name", "", "-name [string] adds a new exchange")
	flag.BoolVar(&websocketSupport, "ws", false, "-websocket adds websocket support")
	flag.BoolVar(&restSupport, "rest", false, "-rest adds REST support")
	flag.BoolVar(&fixSupport, "fix", false, "-fix adds FIX support?")

	flag.Parse()

	fmt.Println("GoCryptoTrader: Exchange templating tool.")

	if newExchangeName == "" || newExchangeName == " " {
		log.Fatal(`GoCryptoTrader: Exchange templating tool exchange name not set e.g. "exchange_template -name [newExchangeNameString]"`)
	}

	if !websocketSupport && !restSupport && !fixSupport {
		log.Fatal(`GoCryptoTrader: Exchange templating tool support not set e.g. "exchange_template -name [newExchangeNameString] [-fix -ws -rest]"`)
	}

	fmt.Println("Exchange Name: ", newExchangeName)
	fmt.Println("Websocket Supported: ", websocketSupport)
	fmt.Println("REST Supported: ", restSupport)
	fmt.Println("FIX Supported: ", fixSupport)
	fmt.Println()
	fmt.Println("Please check if everything is correct then press enter to continue...")

	reader := bufio.NewReader(os.Stdin)
	choice, _, err := reader.ReadRune()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool bufio.reader error ", err)
	}

	if choice != '\n' {
		log.Fatal("GoCryptoTrader: Exchange templating tool stopped...")
	}

	newExchangeName = common.StringToLower(newExchangeName)
	split := strings.Split(newExchangeName, "")
	v := split[0]
	capName := common.StringToUpper(v) + strings.Join(split[1:], "")

	exch := exchange{
		Name:        newExchangeName,
		CapitalName: capName,
		Variable:    v,
		REST:        restSupport,
		WS:          websocketSupport,
		FIX:         fixSupport,
	}

	configTestFile := config.GetConfig()
	err = configTestFile.LoadConfig("../../testdata/configtest.json")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating configuration retrieval error ", err)
	}
	// NOTE need to nullify encrypt configuration

	var configTestExchanges []string

	for _, exch := range configTestFile.Exchanges {
		configTestExchanges = append(configTestExchanges, exch.Name)
	}

	if common.StringDataContainsUpper(configTestExchanges, capName) {
		log.Fatal("GoCryptoTrader: Exchange templating configuration error - exchange already exists")
	}

	newExchConfig := config.ExchangeConfig{}
	newExchConfig.Name = capName
	newExchConfig.Enabled = true
	newExchConfig.RESTPollingDelay = 10
	newExchConfig.APIKey = "Key"
	newExchConfig.APISecret = "Secret"
	newExchConfig.AssetTypes = "SPOT"

	configTestFile.Exchanges = append(configTestFile.Exchanges, newExchConfig)
	// TODO sorting function so exchanges are in alphabetical order - low priority

	err = configTestFile.SaveConfig("../../testdata/configtest.json")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating configuration error - cannot save")
	}

	exchangeDirectory = exchangePackageLocation + newExchangeName + "/"
	exchangeTest = fmt.Sprintf(exchangeDirectory+packageTests, newExchangeName)
	exchangeTypes = fmt.Sprintf(exchangeDirectory+packageTypes, newExchangeName)
	exchangeWrapper = fmt.Sprintf(exchangeDirectory+packageWrapper, newExchangeName)
	exchangeMain = fmt.Sprintf(exchangeDirectory+packageMain, newExchangeName)
	exchangeReadme = exchangeDirectory + packageReadme

	err = os.Mkdir(exchangeDirectory, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot make directory ", err)
	}

	tReadme, err := template.New("readme").ParseFiles("readme_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeReadme)
	r1, err := os.OpenFile(exchangeReadme, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tReadme.Execute(r1, exch)

	tMain, err := template.New("main").ParseFiles("main_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeMain)
	m1, err := os.OpenFile(exchangeMain, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tMain.Execute(m1, exch)

	tTest, err := template.New("test").ParseFiles("test_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeTest)
	t1, err := os.OpenFile(exchangeTest, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tTest.Execute(t1, exch)

	tType, err := template.New("type").ParseFiles("type_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeTypes)
	ty1, err := os.OpenFile(exchangeTypes, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tType.Execute(ty1, exch)

	tWrapper, err := template.New("wrapper").ParseFiles("wrapper_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeWrapper)
	w1, err := os.OpenFile(exchangeWrapper, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tWrapper.Execute(w1, exch)

	err = exec.Command("go", "fmt", exchangeDirectory).Run()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool go fmt error ", err)
	}

	err = exec.Command("go", "fmt", exchangeDirectory).Run()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool go fmt error ", err)
	}

	err = exec.Command("go", "test", exchangeDirectory).Run()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool testing failed ", err)
	}

	fmt.Println("GoCryptoTrader: Exchange templating tool service complete")
	fmt.Println("When wrapper is finished add exchange to exchange.go")
	fmt.Println("Test exchange.go")
	fmt.Println("Update the config_test.go file")
	fmt.Println("Test config.go")
	fmt.Println("Open a pull request")
	fmt.Println("If help is needed please post a message on the slack.")
}

func newFile(path string) {
	_, err := os.Stat(path)

	if os.IsNotExist(err) {
		var file, err = os.Create(path)
		defer file.Close()
		if err != nil {
			log.Fatal("GoCryptoTrader: Exchange templating tool file creation error ", err)
		}
	}
}
<commit_msg>Added logic for file progression under different OS environments.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"html/template"
	"log"
	"os"
	"os/exec"

	"github.com/thrasher-/gocryptotrader/common"
	"github.com/thrasher-/gocryptotrader/config"
)

const (
	packageTests   = "%s_test.go"
	packageTypes   = "%s_types.go"
	packageWrapper = "%s_wrapper.go"
	packageMain    = "%s.go"
	packageReadme  = "README.md"

	exchangePackageLocation = "..%s..%sexchanges%s"
	exchangeLocation        = "..%s..%sexchange.go"
	exchangeConfigPath      = "..%s..%stestdata%sconfigtest.json"
)

var (
	exchangeDirectory string
	exchangeTest      string
	exchangeTypes     string
	exchangeWrapper   string
	exchangeMain      string
	exchangeReadme    string
	exchangeJSON      string
)

type exchange struct {
	Name        string
	CapitalName string
	Variable    string
	REST        bool
	WS          bool
	FIX         bool
}

func main() {
	var newExchangeName string
	var websocketSupport, restSupport, fixSupport bool

	flag.StringVar(&newExchangeName, "name", "", "-name [string] adds a new exchange")
	flag.BoolVar(&websocketSupport, "ws", false, "-websocket adds websocket support")
	flag.BoolVar(&restSupport, "rest", false, "-rest adds REST support")
	flag.BoolVar(&fixSupport, "fix", false, "-fix adds FIX support?")

	flag.Parse()

	fmt.Println("GoCryptoTrader: Exchange templating tool.")

	if newExchangeName == "" || newExchangeName == " " {
		log.Fatal(`GoCryptoTrader: Exchange templating tool exchange name not set e.g. "exchange_template -name [newExchangeNameString]"`)
	}

	if !websocketSupport && !restSupport && !fixSupport {
		log.Fatal(`GoCryptoTrader: Exchange templating tool support not set e.g. "exchange_template -name [newExchangeNameString] [-fix -ws -rest]"`)
	}

	fmt.Println("Exchange Name: ", newExchangeName)
	fmt.Println("Websocket Supported: ", websocketSupport)
	fmt.Println("REST Supported: ", restSupport)
	fmt.Println("FIX Supported: ", fixSupport)
	fmt.Println()
	fmt.Println("Please check if everything is correct then press enter to continue...")

	reader := bufio.NewReader(os.Stdin)
	choice, _, err := reader.ReadRune()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool bufio.reader error ", err)
	}

	if choice != '\n' {
		log.Fatal("GoCryptoTrader: Exchange templating tool stopped...")
	}

	newExchangeName = common.StringToLower(newExchangeName)
	v := newExchangeName[:1]
	capName := common.StringToUpper(v) + newExchangeName[1:]

	exch := exchange{
		Name:        newExchangeName,
		CapitalName: capName,
		Variable:    v,
		REST:        restSupport,
		WS:          websocketSupport,
		FIX:         fixSupport,
	}

	osPathSlash := common.GetOSPathSlash()
	exchangeJSON := fmt.Sprintf(exchangeConfigPath, osPathSlash, osPathSlash, osPathSlash)

	configTestFile := config.GetConfig()
	err = configTestFile.LoadConfig(exchangeJSON)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating configuration retrieval error ", err)
	}
	// NOTE need to nullify encrypt configuration

	var configTestExchanges []string

	for _, exch := range configTestFile.Exchanges {
		configTestExchanges = append(configTestExchanges, exch.Name)
	}

	if common.StringDataContainsUpper(configTestExchanges, capName) {
		log.Fatal("GoCryptoTrader: Exchange templating configuration error - exchange already exists")
	}

	newExchConfig := config.ExchangeConfig{}
	newExchConfig.Name = capName
	newExchConfig.Enabled = true
	newExchConfig.RESTPollingDelay = 10
	newExchConfig.APIKey = "Key"
	newExchConfig.APISecret = "Secret"
	newExchConfig.AssetTypes = "SPOT"

	configTestFile.Exchanges = append(configTestFile.Exchanges, newExchConfig)
	// TODO sorting function so exchanges are in alphabetical order - low priority

	err = configTestFile.SaveConfig(exchangeJSON)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating configuration error - cannot save")
	}

	exchangeDirectory = fmt.Sprintf(
		exchangePackageLocation+newExchangeName+"%s",
		osPathSlash,
		osPathSlash,
		osPathSlash,
		osPathSlash)

	exchangeTest = fmt.Sprintf(exchangeDirectory+packageTests, newExchangeName)
	exchangeTypes = fmt.Sprintf(exchangeDirectory+packageTypes, newExchangeName)
	exchangeWrapper = fmt.Sprintf(exchangeDirectory+packageWrapper, newExchangeName)
	exchangeMain = fmt.Sprintf(exchangeDirectory+packageMain, newExchangeName)
	exchangeReadme = exchangeDirectory + packageReadme

	err = os.Mkdir(exchangeDirectory, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot make directory ", err)
	}

	tReadme, err := template.New("readme").ParseFiles("readme_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeReadme)
	r1, err := os.OpenFile(exchangeReadme, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tReadme.Execute(r1, exch)

	tMain, err := template.New("main").ParseFiles("main_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeMain)
	m1, err := os.OpenFile(exchangeMain, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tMain.Execute(m1, exch)

	tTest, err := template.New("test").ParseFiles("test_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeTest)
	t1, err := os.OpenFile(exchangeTest, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tTest.Execute(t1, exch)

	tType, err := template.New("type").ParseFiles("type_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeTypes)
	ty1, err := os.OpenFile(exchangeTypes, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tType.Execute(ty1, exch)

	tWrapper, err := template.New("wrapper").ParseFiles("wrapper_file.tmpl")
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool error ", err)
	}
	newFile(exchangeWrapper)
	w1, err := os.OpenFile(exchangeWrapper, os.O_WRONLY, 0700)
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool cannot open file ", err)
	}
	tWrapper.Execute(w1, exch)

	err = exec.Command("go", "fmt", exchangeDirectory).Run()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool go fmt error ", err)
	}

	err = exec.Command("go", "test", exchangeDirectory).Run()
	if err != nil {
		log.Fatal("GoCryptoTrader: Exchange templating tool testing failed ", err)
	}

	fmt.Println("GoCryptoTrader: Exchange templating tool service complete")
	fmt.Println("When wrapper is finished add exchange to exchange.go")
	fmt.Println("Test exchange.go")
	fmt.Println("Update the config_test.go file")
	fmt.Println("Test config.go")
	fmt.Println("Open a pull request")
	fmt.Println("If help is needed please post a message on the slack.")
}

func newFile(path string) {
	_, err := os.Stat(path)

	if os.IsNotExist(err) {
		var file, err = os.Create(path)
		defer file.Close()
		if err != nil {
			log.Fatal("GoCryptoTrader: Exchange templating tool file creation error ", err)
		}
	}
}
<|endoftext|>


<commit_before>// +build windows

package collector

import (
	"errors"

	"github.com/StackExchange/wmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
)

func init() {
	registerCollector("cs", NewCSCollector)
}

// A CSCollector is a Prometheus collector for WMI metrics
type CSCollector struct {
	PhysicalMemoryBytes *prometheus.Desc
	LogicalProcessors   *prometheus.Desc
	Hostname            *prometheus.Desc
}

// NewCSCollector ...
func NewCSCollector() (Collector, error) {
	const subsystem = "cs"

	return &CSCollector{
		LogicalProcessors: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "logical_processors"),
			"ComputerSystem.NumberOfLogicalProcessors",
			nil,
			nil,
		),
		PhysicalMemoryBytes: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "physical_memory_bytes"),
			"ComputerSystem.TotalPhysicalMemory",
			nil,
			nil,
		),
		Hostname: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "hostname"),
			"Labeled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain",
			[]string{
				"hostname",
				"domain",
				"fqdn"},
			nil,
		),
	}, nil
}

// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *CSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	if desc, err := c.collect(ch); err != nil {
		log.Error("failed collecting cs metrics:", desc, err)
		return err
	}
	return nil
}

// Win32_ComputerSystem docs:
// - https://msdn.microsoft.com/en-us/library/aa394102
type Win32_ComputerSystem struct {
	NumberOfLogicalProcessors uint32
	TotalPhysicalMemory       uint64
	DNSHostname               string
	Domain                    string
	Workgroup                 string
}

func (c *CSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
	var dst []Win32_ComputerSystem
	q := queryAll(&dst)
	if err := wmi.Query(q, &dst); err != nil {
		return nil, err
	}
	if len(dst) == 0 {
		return nil, errors.New("WMI query returned empty result set")
	}

	ch <- prometheus.MustNewConstMetric(
		c.LogicalProcessors,
		prometheus.GaugeValue,
		float64(dst[0].NumberOfLogicalProcessors),
	)

	ch <- prometheus.MustNewConstMetric(
		c.PhysicalMemoryBytes,
		prometheus.GaugeValue,
		float64(dst[0].TotalPhysicalMemory),
	)

	var fqdn string
	if dst[0].Domain != dst[0].Workgroup {
		fqdn = dst[0].DNSHostname + "." + dst[0].Domain
	} else {
		fqdn = dst[0].DNSHostname
	}

	ch <- prometheus.MustNewConstMetric(
		c.Hostname,
		prometheus.GaugeValue,
		1.0,
		dst[0].DNSHostname,
		dst[0].Domain,
		fqdn,
	)

	return nil, nil
}
<commit_msg>Fix cs collector crashing when running on a domain joined machine<commit_after>// +build windows

package collector

import (
	"errors"

	"github.com/StackExchange/wmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
)

func init() {
	registerCollector("cs", NewCSCollector)
}

// A CSCollector is a Prometheus collector for WMI metrics
type CSCollector struct {
	PhysicalMemoryBytes *prometheus.Desc
	LogicalProcessors   *prometheus.Desc
	Hostname            *prometheus.Desc
}

// NewCSCollector ...
func NewCSCollector() (Collector, error) {
	const subsystem = "cs"

	return &CSCollector{
		LogicalProcessors: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "logical_processors"),
			"ComputerSystem.NumberOfLogicalProcessors",
			nil,
			nil,
		),
		PhysicalMemoryBytes: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "physical_memory_bytes"),
			"ComputerSystem.TotalPhysicalMemory",
			nil,
			nil,
		),
		Hostname: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "hostname"),
			"Labeled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain",
			[]string{
				"hostname",
				"domain",
				"fqdn"},
			nil,
		),
	}, nil
}

// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *CSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
	if desc, err := c.collect(ch); err != nil {
		log.Error("failed collecting cs metrics:", desc, err)
		return err
	}
	return nil
}

// Win32_ComputerSystem docs:
// - https://msdn.microsoft.com/en-us/library/aa394102
type Win32_ComputerSystem struct {
	NumberOfLogicalProcessors uint32
	TotalPhysicalMemory       uint64
	DNSHostname               string
	Domain                    string
	Workgroup                 *string
}

func (c *CSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
	var dst []Win32_ComputerSystem
	q := queryAll(&dst)
	if err := wmi.Query(q, &dst); err != nil {
		return nil, err
	}
	if len(dst) == 0 {
		return nil, errors.New("WMI query returned empty result set")
	}

	ch <- prometheus.MustNewConstMetric(
		c.LogicalProcessors,
		prometheus.GaugeValue,
		float64(dst[0].NumberOfLogicalProcessors),
	)

	ch <- prometheus.MustNewConstMetric(
		c.PhysicalMemoryBytes,
		prometheus.GaugeValue,
		float64(dst[0].TotalPhysicalMemory),
	)

	var fqdn string
	if dst[0].Workgroup == nil || dst[0].Domain != *dst[0].Workgroup {
		fqdn = dst[0].DNSHostname + "." + dst[0].Domain
	} else {
		fqdn = dst[0].DNSHostname
	}

	ch <- prometheus.MustNewConstMetric(
		c.Hostname,
		prometheus.GaugeValue,
		1.0,
		dst[0].DNSHostname,
		dst[0].Domain,
		fqdn,
	)

	return nil, nil
}
<|endoftext|>


<commit_before>package circuitry

import (
	"errors"
	"testing"
	"time"
)

type alwaysFail struct{}

func (c *alwaysFail) Name() string {
	return "always-fail"
}

func (c *alwaysFail) Run() (interface{}, error) {
	return nil, errors.New("fail")
}

func (c *alwaysFail) Fallback() interface{} {
	return "fallback"
}

type alwaysSucceed struct{}

func (c *alwaysSucceed) Name() string {
	return "always-succeed"
}

func (c *alwaysSucceed) Run() (interface{}, error) {
	return "success", nil
}

func (c *alwaysSucceed) Fallback() interface{} {
	return "fallback"
}

func TestAlwaysFail(t *testing.T) {
	b := NewBreaker(40, 0, time.Minute, window())
	v := Execute(&alwaysFail{}, b)
	if v != "fallback" {
		t.Error("didn't execute fallback")
	}
}

func TestAlwaysSucceed(t *testing.T) {
	b := NewBreaker(40, 0, time.Minute, window())
	v := Execute(&alwaysSucceed{}, b)
	if v != "success" {
		t.Error("the fallback was executed")
	}
}
<commit_msg>add execute example<commit_after>package circuitry

import (
	"errors"
	"fmt"
	"testing"
	"time"
)

type alwaysFail struct{}

func (c *alwaysFail) Name() string {
	return "always-fail"
}

func (c *alwaysFail) Run() (interface{}, error) {
	return nil, errors.New("fail")
}

func (c *alwaysFail) Fallback() interface{} {
	return "fallback"
}

type alwaysSucceed struct{}

func (c *alwaysSucceed) Name() string {
	return "always-succeed"
}

func (c *alwaysSucceed) Run() (interface{}, error) {
	return "success", nil
}

func (c *alwaysSucceed) Fallback() interface{} {
	return "fallback"
}

func TestAlwaysFail(t *testing.T) {
	b := NewBreaker(40, 0, time.Minute, window())
	v := Execute(&alwaysFail{}, b)
	if v != "fallback" {
		t.Error("didn't execute fallback")
	}
}

func TestAlwaysSucceed(t *testing.T) {
	b := NewBreaker(40, 0, time.Minute, window())
	v := Execute(&alwaysSucceed{}, b)
	if v != "success" {
		t.Error("the fallback was executed")
	}
}

func ExampleExecute() {
	b := NewBreaker(40, 0, time.Minute, window())
	v := Execute(&alwaysSucceed{}, b)
	fmt.Println(v)
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/leancloud/lean-cli/logo"
	"github.com/leancloud/lean-cli/version"
	"github.com/urfave/cli"
)

// Run the command line
func Run(args []string) {
	// add banner text to help text
	cli.AppHelpTemplate = logo.Logo() + cli.AppHelpTemplate
	cli.SubcommandHelpTemplate = logo.Logo() + cli.SubcommandHelpTemplate

	app := cli.NewApp()
	app.Name = "lean"
	app.Version = version.Version
	app.Usage = "Command line to manage and deploy LeanCloud apps"
	app.EnableBashCompletion = true

	app.CommandNotFound = thirdPartyCommand

	app.Commands = []cli.Command{
		{
			Name:      "login",
			Usage:     "Log in to LeanCloud",
			Action:    wrapAction(loginAction),
			ArgsUsage: "[-u username -p password (--region <CN> | <US> | <TAB>)]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "username,u",
					Usage: "Username",
				},
				cli.StringFlag{
					Name:  "password,p",
					Usage: "Password",
				},
				cli.StringFlag{
					Name:  "region,r",
					Usage: "The LeanCloud region to log in to (e.g., US, CN)",
				},
			},
		},
		{
			Name:      "metric",
			Usage:     "Obtain LeanStorage performance metrics of current project",
			Action:    wrapAction(statusAction),
			ArgsUsage: "[--from fromTime --to toTime --format default|json]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from",
					Usage: "Start date, formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "to",
					Usage: "End date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "format",
					Usage: "Output format，'default' or 'json'",
				},
			},
		},
		{
			Name:   "info",
			Usage:  "Show information about the current user and app",
			Action: wrapAction(infoAction),
		},
		{
			Name:   "up",
			Usage:  "Start a development instance locally",
			Action: wrapAction(upAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Local port to listen on",
					Value: 3000,
				},
				cli.IntFlag{
					Name:  "console-port,c",
					Usage: "Port of the debug console",
				},
				cli.StringFlag{
					Name:  "cmd",
					Usage: "Command to start the project, other arguments except --console-port are ignored",
				},
			},
		},
		{
			Name:      "init",
			Usage:     "Initialize a LeanEngine project",
			Action:    wrapAction(initAction),
			ArgsUsage: "[dest]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "region",
					Usage: "LeanCloud region for the project",
				},
				cli.StringFlag{
					Name:  "group",
					Usage: "LeanEngine group",
				},
			},
		},
		{
			Name:      "switch",
			Usage:     "Change the associated LeanCloud app",
			Action:    wrapAction(switchAction),
			ArgsUsage: "[appID | appName]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "region",
					Usage: "LeanCloud region",
				},
				cli.StringFlag{
					Name:  "group",
					Usage: "LeanEngine group",
				},
			},
		},
		{
			Name:   "deploy",
			Usage:  "Deploy the project to LeanEngine",
			Action: wrapAction(deployAction),
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "g",
					Usage: "Deploy from git repo",
				},
				cli.BoolFlag{
					Name:  "war",
					Usage: "Deploy .war file for Java project. The first .war file in target/ is used by default",
				},
				cli.BoolFlag{
					Name:  "no-cache",
					Usage: "Force download dependencies",
				},
				cli.StringFlag{
					Name:  "leanignore",
					Usage: "Rule file for ignored files in deployment",
					Value: ".leanignore",
				},
				cli.StringFlag{
					Name:  "message,m",
					Usage: "Comment for this deployment, only applicable when deploying from local files",
				},
				cli.BoolFlag{
					Name: "keep-deploy-file",
				},
				cli.StringFlag{
					Name:  "revision,r",
					Usage: "Git revision or branch. Only applicable when deploying from Git",
					Value: "master",
				},
				cli.StringFlag{
					Name:  "options",
					Usage: "Send additional deploy options to server, in urlencode format(like `--options build-root=app&atomic=true`)",
				},
				cli.StringFlag{
					Name:  "prod",
					Usage: "Deploy to production(`--prod 1`) or staging(`--prod 0`) environment, default to staging if it exists",
				},
			},
		},
		{
			Name:   "publish",
			Usage:  "Publish code from staging to production",
			Action: wrapAction(publishAction),
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "options",
					Usage: "Send additional deploy options to server, in urlencode format(like `--options build-root=app&atomic=true`)",
				},
			},
		},
		{
			Name:      "upload",
			Usage:     "Upload files to the current application (available in the '_File' class)",
			Action:    uploadAction,
			ArgsUsage: "<file-path> <file-path> ...",
		},
		{
			Name:   "logs",
			Usage:  "Show LeanEngine logs",
			Action: wrapAction(logsAction),
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "f",
					Usage: "Wait for and continuously show most recent logs",
				},
				cli.StringFlag{
					Name:  "env,e",
					Usage: "Environment to view (staging / production)",
					Value: "production",
				},
				cli.IntFlag{
					Name:  "limit,l",
					Usage: "Maximum number of lines to show",
					Value: 30,
				},
				cli.StringFlag{
					Name:  "from",
					Usage: "Start date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "to",
					Usage: "End date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "format",
					Usage: "Format to use ('default' or 'json')",
					Value: "default",
				},
			},
		},
		{
			Name:   "debug",
			Usage:  "Start the debug console without running the project",
			Action: wrapAction(debugAction),
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "remote,r",
					Usage: "URL of target app",
					Value: "http://localhost:3000",
				},
				cli.StringFlag{
					Name:  "app-id",
					Usage: "Target AppID, use the AppID of the current project by default",
				},
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Port to listen on",
					Value: 3001,
				},
			},
		},
		{
			Name:   "env",
			Usage:  "Output environment variables used by the current project",
			Action: wrapAction(envAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Local port for the app (affects value of LC_APP_PORT)",
					Value: 3000,
				},
				cli.StringFlag{
					Name:  "template",
					Usage: "Template for output, 'export {{name}}={{value}}' by default",
				},
			},
			Subcommands: []cli.Command{
				{
					Name:      "set",
					Usage:     "Set the value of an environment variable",
					Action:    wrapAction(envSetAction),
					ArgsUsage: "[env-name] [env-value]",
				},
				{
					Name:      "unset",
					Usage:     "Delete an environment variable",
					Action:    wrapAction(envUnsetAction),
					ArgsUsage: "[env-name]",
				},
			},
		},
		{
			Name:   "cache",
			Usage:  "LeanCache shell",
			Action: wrapAction(cacheAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "db",
					Usage: "Number of LeanCache DB",
					Value: -1,
				},
				cli.StringFlag{
					Name:  "name",
					Usage: "Name of LeanCache instance",
				},
				cli.StringFlag{
					Name:  "eval",
					Usage: "LeanCache command to run",
				},
			},
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "Show LeanCache instances of the current project",
					Action: wrapAction(cacheListAction),
				},
			},
		},
		{
			Name:   "cql",
			Usage:  "Start CQL interactive mode (warn: CQL is deprecated)",
			Action: wrapAction(cqlAction),
			Flags: []cli.Flag{
				cli.StringFlag{Name: "format,f",
					Usage: "CQL result format",
					Value: "table",
				},
				cli.StringFlag{
					Name:  "eval",
					Usage: "CQL command to run",
				},
			},
		},
		{
			Name:    "help",
			Aliases: []string{"h"},
			Usage:   "Show all commands or help info for one command",
			Action: func(c *cli.Context) error {
				args := c.Args()
				if args.Present() {
					_, err := fmt.Printf("Please use `lean %s -h` for subcommand usage.\n", args.First())
					return err
				}
				return cli.ShowAppHelp(c)
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		disableGA, ok := os.LookupEnv("NO_ANALYTICS")
		var args []string
		if !ok || disableGA == "false" {
			args = []string{"--_collect-stats"}
		}
		args = append(args, c.Args()...)
		err := exec.Command(os.Args[0], args...).Start()
		_ = err
		return nil
	}

	app.Run(args)
}
<commit_msg>fix: unexpected command executing<commit_after>package commands

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/leancloud/lean-cli/logo"
	"github.com/leancloud/lean-cli/version"
	"github.com/urfave/cli"
)

// Run the command line
func Run(args []string) {
	// add banner text to help text
	cli.AppHelpTemplate = logo.Logo() + cli.AppHelpTemplate
	cli.SubcommandHelpTemplate = logo.Logo() + cli.SubcommandHelpTemplate

	app := cli.NewApp()
	app.Name = "lean"
	app.Version = version.Version
	app.Usage = "Command line to manage and deploy LeanCloud apps"
	app.EnableBashCompletion = true

	app.CommandNotFound = thirdPartyCommand

	app.Commands = []cli.Command{
		{
			Name:      "login",
			Usage:     "Log in to LeanCloud",
			Action:    wrapAction(loginAction),
			ArgsUsage: "[-u username -p password (--region <CN> | <US> | <TAB>)]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "username,u",
					Usage: "Username",
				},
				cli.StringFlag{
					Name:  "password,p",
					Usage: "Password",
				},
				cli.StringFlag{
					Name:  "region,r",
					Usage: "The LeanCloud region to log in to (e.g., US, CN)",
				},
			},
		},
		{
			Name:      "metric",
			Usage:     "Obtain LeanStorage performance metrics of current project",
			Action:    wrapAction(statusAction),
			ArgsUsage: "[--from fromTime --to toTime --format default|json]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from",
					Usage: "Start date, formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "to",
					Usage: "End date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "format",
					Usage: "Output format，'default' or 'json'",
				},
			},
		},
		{
			Name:   "info",
			Usage:  "Show information about the current user and app",
			Action: wrapAction(infoAction),
		},
		{
			Name:   "up",
			Usage:  "Start a development instance locally",
			Action: wrapAction(upAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Local port to listen on",
					Value: 3000,
				},
				cli.IntFlag{
					Name:  "console-port,c",
					Usage: "Port of the debug console",
				},
				cli.StringFlag{
					Name:  "cmd",
					Usage: "Command to start the project, other arguments except --console-port are ignored",
				},
			},
		},
		{
			Name:      "init",
			Usage:     "Initialize a LeanEngine project",
			Action:    wrapAction(initAction),
			ArgsUsage: "[dest]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "region",
					Usage: "LeanCloud region for the project",
				},
				cli.StringFlag{
					Name:  "group",
					Usage: "LeanEngine group",
				},
			},
		},
		{
			Name:      "switch",
			Usage:     "Change the associated LeanCloud app",
			Action:    wrapAction(switchAction),
			ArgsUsage: "[appID | appName]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "region",
					Usage: "LeanCloud region",
				},
				cli.StringFlag{
					Name:  "group",
					Usage: "LeanEngine group",
				},
			},
		},
		{
			Name:   "deploy",
			Usage:  "Deploy the project to LeanEngine",
			Action: wrapAction(deployAction),
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "g",
					Usage: "Deploy from git repo",
				},
				cli.BoolFlag{
					Name:  "war",
					Usage: "Deploy .war file for Java project. The first .war file in target/ is used by default",
				},
				cli.BoolFlag{
					Name:  "no-cache",
					Usage: "Force download dependencies",
				},
				cli.StringFlag{
					Name:  "leanignore",
					Usage: "Rule file for ignored files in deployment",
					Value: ".leanignore",
				},
				cli.StringFlag{
					Name:  "message,m",
					Usage: "Comment for this deployment, only applicable when deploying from local files",
				},
				cli.BoolFlag{
					Name: "keep-deploy-file",
				},
				cli.StringFlag{
					Name:  "revision,r",
					Usage: "Git revision or branch. Only applicable when deploying from Git",
					Value: "master",
				},
				cli.StringFlag{
					Name:  "options",
					Usage: "Send additional deploy options to server, in urlencode format(like `--options build-root=app&atomic=true`)",
				},
				cli.StringFlag{
					Name:  "prod",
					Usage: "Deploy to production(`--prod 1`) or staging(`--prod 0`) environment, default to staging if it exists",
				},
			},
		},
		{
			Name:   "publish",
			Usage:  "Publish code from staging to production",
			Action: wrapAction(publishAction),
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "options",
					Usage: "Send additional deploy options to server, in urlencode format(like `--options build-root=app&atomic=true`)",
				},
			},
		},
		{
			Name:      "upload",
			Usage:     "Upload files to the current application (available in the '_File' class)",
			Action:    uploadAction,
			ArgsUsage: "<file-path> <file-path> ...",
		},
		{
			Name:   "logs",
			Usage:  "Show LeanEngine logs",
			Action: wrapAction(logsAction),
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "f",
					Usage: "Wait for and continuously show most recent logs",
				},
				cli.StringFlag{
					Name:  "env,e",
					Usage: "Environment to view (staging / production)",
					Value: "production",
				},
				cli.IntFlag{
					Name:  "limit,l",
					Usage: "Maximum number of lines to show",
					Value: 30,
				},
				cli.StringFlag{
					Name:  "from",
					Usage: "Start date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "to",
					Usage: "End date formatted as YYYY-MM-DD，e.g., 1926-08-17",
				},
				cli.StringFlag{
					Name:  "format",
					Usage: "Format to use ('default' or 'json')",
					Value: "default",
				},
			},
		},
		{
			Name:   "debug",
			Usage:  "Start the debug console without running the project",
			Action: wrapAction(debugAction),
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "remote,r",
					Usage: "URL of target app",
					Value: "http://localhost:3000",
				},
				cli.StringFlag{
					Name:  "app-id",
					Usage: "Target AppID, use the AppID of the current project by default",
				},
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Port to listen on",
					Value: 3001,
				},
			},
		},
		{
			Name:   "env",
			Usage:  "Output environment variables used by the current project",
			Action: wrapAction(envAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "port,p",
					Usage: "Local port for the app (affects value of LC_APP_PORT)",
					Value: 3000,
				},
				cli.StringFlag{
					Name:  "template",
					Usage: "Template for output, 'export {{name}}={{value}}' by default",
				},
			},
			Subcommands: []cli.Command{
				{
					Name:      "set",
					Usage:     "Set the value of an environment variable",
					Action:    wrapAction(envSetAction),
					ArgsUsage: "[env-name] [env-value]",
				},
				{
					Name:      "unset",
					Usage:     "Delete an environment variable",
					Action:    wrapAction(envUnsetAction),
					ArgsUsage: "[env-name]",
				},
			},
		},
		{
			Name:   "cache",
			Usage:  "LeanCache shell",
			Action: wrapAction(cacheAction),
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "db",
					Usage: "Number of LeanCache DB",
					Value: -1,
				},
				cli.StringFlag{
					Name:  "name",
					Usage: "Name of LeanCache instance",
				},
				cli.StringFlag{
					Name:  "eval",
					Usage: "LeanCache command to run",
				},
			},
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "Show LeanCache instances of the current project",
					Action: wrapAction(cacheListAction),
				},
			},
		},
		{
			Name:   "cql",
			Usage:  "Start CQL interactive mode (warn: CQL is deprecated)",
			Action: wrapAction(cqlAction),
			Flags: []cli.Flag{
				cli.StringFlag{Name: "format,f",
					Usage: "CQL result format",
					Value: "table",
				},
				cli.StringFlag{
					Name:  "eval",
					Usage: "CQL command to run",
				},
			},
		},
		{
			Name:    "help",
			Aliases: []string{"h"},
			Usage:   "Show all commands or help info for one command",
			Action: func(c *cli.Context) error {
				args := c.Args()
				if args.Present() {
					_, err := fmt.Printf("Please use `lean %s -h` for subcommand usage.\n", args.First())
					return err
				}
				return cli.ShowAppHelp(c)
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		disableGA, ok := os.LookupEnv("NO_ANALYTICS")
		if !ok || disableGA == "false" {
			args = []string{"--_collect-stats"}
			args = append(args, c.Args()...)
			_ = exec.Command(os.Args[0], args...).Start()
		}
		return nil
	}

	app.Run(args)
}
<|endoftext|>