<commit_before>// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gtime

import (
	"bytes"
	"github.com/gogf/gf/g/text/gregex"
	"github.com/gogf/gf/g/text/gstr"
	"strings"
)

var (
	// 参考：http://php.net/manual/zh/function.date.php
	formats = map[byte]string{
		// ================== 日 ==================
		'd': "02",     // 月份中的第几天，有前导零的 2 位数字(01 到 31)
		'D': "Mon",    // 星期中的第几天，文本表示，3 个字母(Mon 到 Sun)
		'w': "Monday", // 星期中的第几天，数字型式的文本表示 0为星期天 6为星期六
		'N': "Monday", // ISO-8601 格式数字表示的星期中的第几天 1（表示星期一）到 7（表示星期天）
		'j': "=j=02",  // 月份中的第几天，没有前导零(1 到 31)
		'S': "02",     // 每月天数后面的英文后缀，2 个字符 st，nd，rd 或者 th。可以和 j 一起用
		'l': "Monday", // ("L"的小写字母)星期几，完整的文本格式(Sunday 到 Saturday)

		// ================== 月 ==================
		'F': "January", // 月份，完整的文本格式，例如 January 或者 March	January 到 December
		'm': "01",      // 数字表示的月份，有前导零(01 到 12)
		'M': "Jan",     // 三个字母缩写表示的月份(Jan 到 Dec)
		'n': "1",       // 数字表示的月份，没有前导零(1 到 12)

		// ================== 年 ==================
		'Y': "2006", // 4 位数字完整表示的年份, 例如：1999 或 2003
		'y': "06",   // 2 位数字表示的年份, 例如：99 或 03

		// ================== 时间 ==================
		'a': "pm",      // 小写的上午和下午值	am 或 pm
		'A': "PM",      // 大写的上午和下午值	AM 或 PM
		'g': "3",       // 小时，12 小时格式，没有前导零,  1 到 12
		'G': "=G=15",   // 小时，24 小时格式，没有前导零,  0 到 23
		'h': "03",      // 小时，12 小时格式，有前导零,   01 到 12
		'H': "15",      // 小时，24 小时格式，有前导零,   00 到 23
		'i': "04",      // 有前导零的分钟数, 00 到 59
		's': "05",      // 秒数，有前导零,   00 到 59
		'u': "=u=.000", // 毫秒(3位)

		// ================== 时区 ==================
		'O': "-0700",  // 与UTC相差的小时数, 例如：+0200
		'P': "-07:00", // 与UTC的差别，小时和分钟之间有冒号分隔, 例如：+02:00
		'T': "MST",    // 时区缩写, 例如：UTC，GMT，CST

		// ================== 完整的日期／时间 ==================
		'c': "2006-01-02T15:04:05-07:00", // ISO 8601 格式的日期，例如：2004-02-12T15:19:21+00:00
		'r': "Mon, 02 Jan 06 15:04 MST",  // RFC 822 格式的日期，例如：Thu, 21 Dec 2000 16:01:07 +0200
	}

	// 星期的英文值和数字值对应map
	weekMap = map[string]string{
		"Sunday":    "0",
		"Monday":    "1",
		"Tuesday":   "2",
		"Wednesday": "3",
		"Thursday":  "4",
		"Friday":    "5",
		"Saturday":  "6",
	}

	// 月份中的第几天数字值和英文值对应map, 最后一个数字为0或大于4时 都为'th'
	monthDayMap = map[string]string{
		"1": "st",
		"2": "nd",
		"3": "rd",
		"4": "th",
	}
)

// 将自定义的格式转换为标准库时间格式
func formatToStdLayout(format string) string {
	b := bytes.NewBuffer(nil)
	for i := 0; i < len(format); {
		switch format[i] {
		case '\\':
			if i < len(format)-1 {
				b.WriteByte(format[i+1])
				i += 2
				continue
			} else {
				return b.String()
			}

		default:
			if f, ok := formats[format[i]]; ok {
				// 有几个转换的符号需要特殊处理
				switch format[i] {
				case 'j':
					b.WriteString("02")
				case 'G':
					b.WriteString("15")
				case 'u':
					if i > 0 && format[i-1] == '.' {
						b.WriteString("000")
					} else {
						b.WriteString(".000")
					}

				default:
					b.WriteString(f)
				}
			} else {
				b.WriteByte(format[i])
			}
			i++
		}
	}
	return b.String()
}

// 将format格式转换为正则表达式规则
func formatToRegexPattern(format string) string {
	s := gregex.Quote(formatToStdLayout(format))
	s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)
	s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)
	return s
}

// 格式化，使用自定义日期格式
func (t *Time) Format(format string) string {
	runes := []rune(format)
	buffer := bytes.NewBuffer(nil)
	for i := 0; i < len(runes); {
		switch runes[i] {
		case '\\':
			if i < len(runes)-1 {
				buffer.WriteRune(runes[i+1])
				i += 2
				continue
			} else {
				return buffer.String()
			}

		default:
			if runes[i] > 255 {
				buffer.WriteRune(runes[i])
				break
			}
			if f, ok := formats[byte(runes[i])]; ok {
				result := t.Time.Format(f)
				// 有几个转换的符号需要特殊处理
				switch runes[i] {
				case 'j':
					buffer.WriteString(gstr.ReplaceByArray(result, []string{"=j=0", "", "=j=", ""}))
				case 'G':
					buffer.WriteString(gstr.ReplaceByArray(result, []string{"=G=0", "", "=G=", ""}))
				case 'u':
					buffer.WriteString(strings.Replace(result, "=u=.", "", -1))
				case 'w':
					buffer.WriteString(weekMap[result])
				case 'N':
					buffer.WriteString(strings.Replace(weekMap[result], "0", "7", -1))
				case 'S':
					buffer.WriteString(formatMonthDayMap(result[1:]))
				default:
					buffer.WriteString(result)
				}
			} else {
				buffer.WriteRune(runes[i])
			}
		}
		i++
	}
	return buffer.String()
}

func formatMonthDayMap(days string) string {
	if days > "4" || days == "0" {
		return monthDayMap["4"]
	} else {
		return monthDayMap[days]
	}
}

// 格式化，使用标准库格式
func (t *Time) Layout(layout string) string {
	return t.Time.Format(layout)
}
<commit_msg>use golint checked<commit_after>// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gtime

import (
	"bytes"
	"github.com/gogf/gf/g/text/gregex"
	"github.com/gogf/gf/g/text/gstr"
	"strings"
)

var (
	// 参考：http://php.net/manual/zh/function.date.php
	formats = map[byte]string{
		// ================== 日 ==================
		'd': "02",     // 月份中的第几天，有前导零的 2 位数字(01 到 31)
		'D': "Mon",    // 星期中的第几天，文本表示，3 个字母(Mon 到 Sun)
		'w': "Monday", // 星期中的第几天，数字型式的文本表示 0为星期天 6为星期六
		'N': "Monday", // ISO-8601 格式数字表示的星期中的第几天 1（表示星期一）到 7（表示星期天）
		'j': "=j=02",  // 月份中的第几天，没有前导零(1 到 31)
		'S': "02",     // 每月天数后面的英文后缀，2 个字符 st，nd，rd 或者 th。可以和 j 一起用
		'l': "Monday", // ("L"的小写字母)星期几，完整的文本格式(Sunday 到 Saturday)

		// ================== 月 ==================
		'F': "January", // 月份，完整的文本格式，例如 January 或者 March	January 到 December
		'm': "01",      // 数字表示的月份，有前导零(01 到 12)
		'M': "Jan",     // 三个字母缩写表示的月份(Jan 到 Dec)
		'n': "1",       // 数字表示的月份，没有前导零(1 到 12)

		// ================== 年 ==================
		'Y': "2006", // 4 位数字完整表示的年份, 例如：1999 或 2003
		'y': "06",   // 2 位数字表示的年份, 例如：99 或 03

		// ================== 时间 ==================
		'a': "pm",      // 小写的上午和下午值	am 或 pm
		'A': "PM",      // 大写的上午和下午值	AM 或 PM
		'g': "3",       // 小时，12 小时格式，没有前导零,  1 到 12
		'G': "=G=15",   // 小时，24 小时格式，没有前导零,  0 到 23
		'h': "03",      // 小时，12 小时格式，有前导零,   01 到 12
		'H': "15",      // 小时，24 小时格式，有前导零,   00 到 23
		'i': "04",      // 有前导零的分钟数, 00 到 59
		's': "05",      // 秒数，有前导零,   00 到 59
		'u': "=u=.000", // 毫秒(3位)

		// ================== 时区 ==================
		'O': "-0700",  // 与UTC相差的小时数, 例如：+0200
		'P': "-07:00", // 与UTC的差别，小时和分钟之间有冒号分隔, 例如：+02:00
		'T': "MST",    // 时区缩写, 例如：UTC，GMT，CST

		// ================== 完整的日期／时间 ==================
		'c': "2006-01-02T15:04:05-07:00", // ISO 8601 格式的日期，例如：2004-02-12T15:19:21+00:00
		'r': "Mon, 02 Jan 06 15:04 MST",  // RFC 822 格式的日期，例如：Thu, 21 Dec 2000 16:01:07 +0200
	}

	// 星期的英文值和数字值对应map
	weekMap = map[string]string{
		"Sunday":    "0",
		"Monday":    "1",
		"Tuesday":   "2",
		"Wednesday": "3",
		"Thursday":  "4",
		"Friday":    "5",
		"Saturday":  "6",
	}

	// 月份中的第几天数字值和英文值对应map, 最后一个数字为0或大于4时 都为'th'
	monthDayMap = map[string]string{
		"1": "st",
		"2": "nd",
		"3": "rd",
		"4": "th",
	}
)

// 将自定义的格式转换为标准库时间格式
func formatToStdLayout(format string) string {
	b := bytes.NewBuffer(nil)
	for i := 0; i < len(format); {
		switch format[i] {
		case '\\':
			if i < len(format)-1 {
				b.WriteByte(format[i+1])
				i += 2
				continue
			} else {
				return b.String()
			}

		default:
			if f, ok := formats[format[i]]; ok {
				// 有几个转换的符号需要特殊处理
				switch format[i] {
				case 'j':
					b.WriteString("02")
				case 'G':
					b.WriteString("15")
				case 'u':
					if i > 0 && format[i-1] == '.' {
						b.WriteString("000")
					} else {
						b.WriteString(".000")
					}

				default:
					b.WriteString(f)
				}
			} else {
				b.WriteByte(format[i])
			}
			i++
		}
	}
	return b.String()
}

// 将format格式转换为正则表达式规则
func formatToRegexPattern(format string) string {
	s := gregex.Quote(formatToStdLayout(format))
	s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)
	s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)
	return s
}

// 格式化，使用自定义日期格式
func (t *Time) Format(format string) string {
	runes := []rune(format)
	buffer := bytes.NewBuffer(nil)
	for i := 0; i < len(runes); {
		switch runes[i] {
		case '\\':
			if i < len(runes)-1 {
				buffer.WriteRune(runes[i+1])
				i += 2
				continue
			} else {
				return buffer.String()
			}

		default:
			if runes[i] > 255 {
				buffer.WriteRune(runes[i])
				break
			}
			if f, ok := formats[byte(runes[i])]; ok {
				result := t.Time.Format(f)
				// 有几个转换的符号需要特殊处理
				switch runes[i] {
				case 'j':
					buffer.WriteString(gstr.ReplaceByArray(result, []string{"=j=0", "", "=j=", ""}))
				case 'G':
					buffer.WriteString(gstr.ReplaceByArray(result, []string{"=G=0", "", "=G=", ""}))
				case 'u':
					buffer.WriteString(strings.Replace(result, "=u=.", "", -1))
				case 'w':
					buffer.WriteString(weekMap[result])
				case 'N':
					buffer.WriteString(strings.Replace(weekMap[result], "0", "7", -1))
				case 'S':
					buffer.WriteString(formatMonthDayMap(result[1:]))
				default:
					buffer.WriteString(result)
				}
			} else {
				buffer.WriteRune(runes[i])
			}
		}
		i++
	}
	return buffer.String()
}

func formatMonthDayMap(days string) string {
	if days > "4" || days == "0" {
		return monthDayMap["4"]
	}
	return monthDayMap[days]
}

// 格式化，使用标准库格式
func (t *Time) Layout(layout string) string {
	return t.Time.Format(layout)
}
<|endoftext|>


<commit_before>package maint

import (
	"flag"
	"fmt"
	"strings"

	"github.com/hashicorp/consul/command/flags"
	"github.com/mitchellh/cli"
)

// cmd is a Command implementation that enables or disables
// node or service maintenance mode.
type cmd struct {
	UI    cli.Ui
	help  string
	flags *flag.FlagSet
	http  *flags.HTTPFlags

	// flags
	enable    bool
	disable   bool
	reason    string
	serviceID string
}

func New(ui cli.Ui) *cmd {
	c := &cmd{UI: ui}
	c.init()
	return c
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.BoolVar(&c.enable, "enable", false,
		"Enable maintenance mode.")
	c.flags.BoolVar(&c.disable, "disable", false,
		"Disable maintenance mode.")
	c.flags.StringVar(&c.reason, "reason", "",
		"Text describing the maintenance reason.")
	c.flags.StringVar(&c.serviceID, "service", "",
		"Control maintenance mode for a specific service ID.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	if err := c.flags.Parse(args); err != nil {
		return 1
	}

	// Ensure we don't have conflicting args
	if c.enable && c.disable {
		c.UI.Error("Only one of -enable or -disable may be provided")
		return 1
	}
	if !c.enable && c.reason != "" {
		c.UI.Error("Reason may only be provided with -enable")
		return 1
	}
	if !c.enable && !c.disable && c.serviceID != "" {
		c.UI.Error("Service requires either -enable or -disable")
		return 1
	}

	// Create and test the HTTP client
	client, err := c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}
	a := client.Agent()
	nodeName, err := a.NodeName()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
		return 1
	}

	if !c.enable && !c.disable {
		// List mode - list nodes/services in maintenance mode
		checks, err := a.Checks()
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error getting checks: %s", err))
			return 1
		}

		for _, check := range checks {
			if check.CheckID == "_node_maintenance" {
				c.UI.Output("Node:")
				c.UI.Output("  Name:   " + nodeName)
				c.UI.Output("  Reason: " + check.Notes)
				c.UI.Output("")
			} else if strings.HasPrefix(check.CheckID, "_service_maintenance:") {
				c.UI.Output("Service:")
				c.UI.Output("  ID:     " + check.ServiceID)
				c.UI.Output("  Reason: " + check.Notes)
				c.UI.Output("")
			}
		}

		return 0
	}

	if c.enable {
		// Enable node maintenance
		if c.serviceID == "" {
			if err := a.EnableNodeMaintenance(c.reason); err != nil {
				c.UI.Error(fmt.Sprintf("Error enabling node maintenance: %s", err))
				return 1
			}
			c.UI.Output("Node maintenance is now enabled")
			return 0
		}

		// Enable service maintenance
		if err := a.EnableServiceMaintenance(c.serviceID, c.reason); err != nil {
			c.UI.Error(fmt.Sprintf("Error enabling service maintenance: %s", err))
			return 1
		}
		c.UI.Output(fmt.Sprintf("Service maintenance is now enabled for %q", c.serviceID))
		return 0
	}

	if c.disable {
		// Disable node maintenance
		if c.serviceID == "" {
			if err := a.DisableNodeMaintenance(); err != nil {
				c.UI.Error(fmt.Sprintf("Error disabling node maintenance: %s", err))
				return 1
			}
			c.UI.Output("Node maintenance is now disabled")
			return 0
		}

		// Disable service maintenance
		if err := a.DisableServiceMaintenance(c.serviceID); err != nil {
			c.UI.Error(fmt.Sprintf("Error disabling service maintenance: %s", err))
			return 1
		}
		c.UI.Output(fmt.Sprintf("Service maintenance is now disabled for %q", c.serviceID))
		return 0
	}

	return 0
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Controls node or service maintenance mode"
const help = `
Usage: consul maint [options]

  Places a node or service into maintenance mode. During maintenance mode,
  the node or service will be excluded from all queries through the DNS
  or API interfaces, effectively taking it out of the pool of available
  nodes. This is done by registering an additional critical health check.

  When enabling maintenance mode for a node or service, you may optionally
  specify a reason string. This string will appear in the "Notes" field
  of the critical health check which is registered against the node or
  service. If no reason is provided, a default value will be used.

  Maintenance mode is persistent, and will be restored in the event of an
  agent restart. It is therefore required to disable maintenance mode on
  a given node or service before it will be placed back into the pool.

  By default, we operate on the node as a whole. By specifying the
  "-service" argument, this behavior can be changed to enable or disable
  only a specific service.

  If no arguments are given, the agent's maintenance status will be shown.
  This will return blank if nothing is currently under maintenance.
`
<commit_msg>remove nodeName call when using -service<commit_after>package maint

import (
	"flag"
	"fmt"
	"strings"

	"github.com/hashicorp/consul/command/flags"
	"github.com/mitchellh/cli"
)

// cmd is a Command implementation that enables or disables
// node or service maintenance mode.
type cmd struct {
	UI    cli.Ui
	help  string
	flags *flag.FlagSet
	http  *flags.HTTPFlags

	// flags
	enable    bool
	disable   bool
	reason    string
	serviceID string
}

func New(ui cli.Ui) *cmd {
	c := &cmd{UI: ui}
	c.init()
	return c
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.BoolVar(&c.enable, "enable", false,
		"Enable maintenance mode.")
	c.flags.BoolVar(&c.disable, "disable", false,
		"Disable maintenance mode.")
	c.flags.StringVar(&c.reason, "reason", "",
		"Text describing the maintenance reason.")
	c.flags.StringVar(&c.serviceID, "service", "",
		"Control maintenance mode for a specific service ID.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	if err := c.flags.Parse(args); err != nil {
		return 1
	}

	// Ensure we don't have conflicting args
	if c.enable && c.disable {
		c.UI.Error("Only one of -enable or -disable may be provided")
		return 1
	}
	if !c.enable && c.reason != "" {
		c.UI.Error("Reason may only be provided with -enable")
		return 1
	}
	if !c.enable && !c.disable && c.serviceID != "" {
		c.UI.Error("Service requires either -enable or -disable")
		return 1
	}

	// Create and test the HTTP client
	client, err := c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}
	a := client.Agent()

	if !c.enable && !c.disable {
		nodeName, err := a.NodeName()
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error querying Consul agent: %s", err))
			return 1
		}

		// List mode - list nodes/services in maintenance mode
		checks, err := a.Checks()
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error getting checks: %s", err))
			return 1
		}

		for _, check := range checks {
			if check.CheckID == "_node_maintenance" {
				c.UI.Output("Node:")
				c.UI.Output("  Name:   " + nodeName)
				c.UI.Output("  Reason: " + check.Notes)
				c.UI.Output("")
			} else if strings.HasPrefix(check.CheckID, "_service_maintenance:") {
				c.UI.Output("Service:")
				c.UI.Output("  ID:     " + check.ServiceID)
				c.UI.Output("  Reason: " + check.Notes)
				c.UI.Output("")
			}
		}

		return 0
	}

	if c.enable {
		// Enable node maintenance
		if c.serviceID == "" {
			if err := a.EnableNodeMaintenance(c.reason); err != nil {
				c.UI.Error(fmt.Sprintf("Error enabling node maintenance: %s", err))
				return 1
			}
			c.UI.Output("Node maintenance is now enabled")
			return 0
		}

		// Enable service maintenance
		if err := a.EnableServiceMaintenance(c.serviceID, c.reason); err != nil {
			c.UI.Error(fmt.Sprintf("Error enabling service maintenance: %s", err))
			return 1
		}
		c.UI.Output(fmt.Sprintf("Service maintenance is now enabled for %q", c.serviceID))
		return 0
	}

	if c.disable {
		// Disable node maintenance
		if c.serviceID == "" {
			if err := a.DisableNodeMaintenance(); err != nil {
				c.UI.Error(fmt.Sprintf("Error disabling node maintenance: %s", err))
				return 1
			}
			c.UI.Output("Node maintenance is now disabled")
			return 0
		}

		// Disable service maintenance
		if err := a.DisableServiceMaintenance(c.serviceID); err != nil {
			c.UI.Error(fmt.Sprintf("Error disabling service maintenance: %s", err))
			return 1
		}
		c.UI.Output(fmt.Sprintf("Service maintenance is now disabled for %q", c.serviceID))
		return 0
	}

	return 0
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Controls node or service maintenance mode"
const help = `
Usage: consul maint [options]

  Places a node or service into maintenance mode. During maintenance mode,
  the node or service will be excluded from all queries through the DNS
  or API interfaces, effectively taking it out of the pool of available
  nodes. This is done by registering an additional critical health check.

  When enabling maintenance mode for a node or service, you may optionally
  specify a reason string. This string will appear in the "Notes" field
  of the critical health check which is registered against the node or
  service. If no reason is provided, a default value will be used.

  Maintenance mode is persistent, and will be restored in the event of an
  agent restart. It is therefore required to disable maintenance mode on
  a given node or service before it will be placed back into the pool.

  By default, we operate on the node as a whole. By specifying the
  "-service" argument, this behavior can be changed to enable or disable
  only a specific service.

  If no arguments are given, the agent's maintenance status will be shown.
  This will return blank if nothing is currently under maintenance.
`
<|endoftext|>


<commit_before>package system

import (
	"fmt"
	"strings"
	"time"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/utils/templates"
	"github.com/docker/go-units"
	"github.com/spf13/cobra"
)

type infoOptions struct {
	format string
}

// NewInfoCommand creates a new cobra.Command for `docker info`
func NewInfoCommand(dockerCli *command.DockerCli) *cobra.Command {
	var opts infoOptions

	cmd := &cobra.Command{
		Use:   "info [OPTIONS]",
		Short: "Display system-wide information",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runInfo(dockerCli, &opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")

	return cmd
}

func runInfo(dockerCli *command.DockerCli, opts *infoOptions) error {
	ctx := context.Background()
	info, err := dockerCli.Client().Info(ctx)
	if err != nil {
		return err
	}
	if opts.format == "" {
		return prettyPrintInfo(dockerCli, info)
	}
	return formatInfo(dockerCli, info, opts.format)
}

func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
	fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers)
	fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning)
	fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused)
	fmt.Fprintf(dockerCli.Out(), " Stopped: %d\n", info.ContainersStopped)
	fmt.Fprintf(dockerCli.Out(), "Images: %d\n", info.Images)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Server Version: %s\n", info.ServerVersion)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Storage Driver: %s\n", info.Driver)
	if info.DriverStatus != nil {
		for _, pair := range info.DriverStatus {
			fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1])

			// print a warning if devicemapper is using a loopback file
			if pair[0] == "Data loop file" {
				fmt.Fprintln(dockerCli.Err(), " WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.")
			}
		}

	}
	if info.SystemStatus != nil {
		for _, pair := range info.SystemStatus {
			fmt.Fprintf(dockerCli.Out(), "%s: %s\n", pair[0], pair[1])
		}
	}
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver)

	fmt.Fprintf(dockerCli.Out(), "Plugins: \n")
	fmt.Fprintf(dockerCli.Out(), " Volume:")
	fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " "))
	fmt.Fprintf(dockerCli.Out(), "\n")
	fmt.Fprintf(dockerCli.Out(), " Network:")
	fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Network, " "))
	fmt.Fprintf(dockerCli.Out(), "\n")

	if len(info.Plugins.Authorization) != 0 {
		fmt.Fprintf(dockerCli.Out(), " Authorization:")
		fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Authorization, " "))
		fmt.Fprintf(dockerCli.Out(), "\n")
	}

	fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState)
	if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive {
		fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID)
		if info.Swarm.Error != "" {
			fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error)
		}
		fmt.Fprintf(dockerCli.Out(), " Is Manager: %v\n", info.Swarm.ControlAvailable)
		if info.Swarm.ControlAvailable {
			fmt.Fprintf(dockerCli.Out(), " ClusterID: %s\n", info.Swarm.Cluster.ID)
			fmt.Fprintf(dockerCli.Out(), " Managers: %d\n", info.Swarm.Managers)
			fmt.Fprintf(dockerCli.Out(), " Nodes: %d\n", info.Swarm.Nodes)
			fmt.Fprintf(dockerCli.Out(), " Orchestration:\n")
			taskHistoryRetentionLimit := int64(0)
			if info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit != nil {
				taskHistoryRetentionLimit = *info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit
			}
			fmt.Fprintf(dockerCli.Out(), "  Task History Retention Limit: %d\n", taskHistoryRetentionLimit)
			fmt.Fprintf(dockerCli.Out(), " Raft:\n")
			fmt.Fprintf(dockerCli.Out(), "  Snapshot Interval: %d\n", info.Swarm.Cluster.Spec.Raft.SnapshotInterval)
			fmt.Fprintf(dockerCli.Out(), "  Heartbeat Tick: %d\n", info.Swarm.Cluster.Spec.Raft.HeartbeatTick)
			fmt.Fprintf(dockerCli.Out(), "  Election Tick: %d\n", info.Swarm.Cluster.Spec.Raft.ElectionTick)
			fmt.Fprintf(dockerCli.Out(), " Dispatcher:\n")
			fmt.Fprintf(dockerCli.Out(), "  Heartbeat Period: %s\n", units.HumanDuration(time.Duration(info.Swarm.Cluster.Spec.Dispatcher.HeartbeatPeriod)))
			fmt.Fprintf(dockerCli.Out(), " CA Configuration:\n")
			fmt.Fprintf(dockerCli.Out(), "  Expiry Duration: %s\n", units.HumanDuration(info.Swarm.Cluster.Spec.CAConfig.NodeCertExpiry))
			if len(info.Swarm.Cluster.Spec.CAConfig.ExternalCAs) > 0 {
				fmt.Fprintf(dockerCli.Out(), "  External CAs:\n")
				for _, entry := range info.Swarm.Cluster.Spec.CAConfig.ExternalCAs {
					fmt.Fprintf(dockerCli.Out(), "    %s: %s\n", entry.Protocol, entry.URL)
				}
			}
		}
		fmt.Fprintf(dockerCli.Out(), " Node Address: %s\n", info.Swarm.NodeAddr)
	}

	if len(info.Runtimes) > 0 {
		fmt.Fprintf(dockerCli.Out(), "Runtimes:")
		for name := range info.Runtimes {
			fmt.Fprintf(dockerCli.Out(), " %s", name)
		}
		fmt.Fprint(dockerCli.Out(), "\n")
		fmt.Fprintf(dockerCli.Out(), "Default Runtime: %s\n", info.DefaultRuntime)
	}

	if info.OSType == "linux" {
		fmt.Fprintf(dockerCli.Out(), "Security Options:")
		ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " "))
		fmt.Fprintf(dockerCli.Out(), "\n")
	}

	// Isolation only has meaning on a Windows daemon.
	if info.OSType == "windows" {
		fmt.Fprintf(dockerCli.Out(), "Default Isolation: %v\n", info.Isolation)
	}

	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Kernel Version: %s\n", info.KernelVersion)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Operating System: %s\n", info.OperatingSystem)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "OSType: %s\n", info.OSType)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Architecture: %s\n", info.Architecture)
	fmt.Fprintf(dockerCli.Out(), "CPUs: %d\n", info.NCPU)
	fmt.Fprintf(dockerCli.Out(), "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Name: %s\n", info.Name)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "ID: %s\n", info.ID)
	fmt.Fprintf(dockerCli.Out(), "Docker Root Dir: %s\n", info.DockerRootDir)
	fmt.Fprintf(dockerCli.Out(), "Debug Mode (client): %v\n", utils.IsDebugEnabled())
	fmt.Fprintf(dockerCli.Out(), "Debug Mode (server): %v\n", info.Debug)

	if info.Debug {
		fmt.Fprintf(dockerCli.Out(), " File Descriptors: %d\n", info.NFd)
		fmt.Fprintf(dockerCli.Out(), " Goroutines: %d\n", info.NGoroutines)
		fmt.Fprintf(dockerCli.Out(), " System Time: %s\n", info.SystemTime)
		fmt.Fprintf(dockerCli.Out(), " EventsListeners: %d\n", info.NEventsListener)
	}

	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Http Proxy: %s\n", info.HTTPProxy)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Https Proxy: %s\n", info.HTTPSProxy)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "No Proxy: %s\n", info.NoProxy)

	if info.IndexServerAddress != "" {
		u := dockerCli.ConfigFile().AuthConfigs[info.IndexServerAddress].Username
		if len(u) > 0 {
			fmt.Fprintf(dockerCli.Out(), "Username: %v\n", u)
		}
		fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress)
	}

	// Only output these warnings if the server does not support these features
	if info.OSType != "windows" {
		if !info.MemoryLimit {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support")
		}
		if !info.SwapLimit {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support")
		}
		if !info.KernelMemory {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support")
		}
		if !info.OomKillDisable {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support")
		}
		if !info.CPUCfsQuota {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support")
		}
		if !info.CPUCfsPeriod {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support")
		}
		if !info.CPUShares {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support")
		}
		if !info.CPUSet {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support")
		}
		if !info.IPv4Forwarding {
			fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled")
		}
		if !info.BridgeNfIptables {
			fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled")
		}
		if !info.BridgeNfIP6tables {
			fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled")
		}
	}

	if info.Labels != nil {
		fmt.Fprintln(dockerCli.Out(), "Labels:")
		for _, attribute := range info.Labels {
			fmt.Fprintf(dockerCli.Out(), " %s\n", attribute)
		}
	}

	ioutils.FprintfIfTrue(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild)
	if info.ClusterStore != "" {
		fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore)
	}

	if info.ClusterAdvertise != "" {
		fmt.Fprintf(dockerCli.Out(), "Cluster Advertise: %s\n", info.ClusterAdvertise)
	}

	if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) {
		fmt.Fprintln(dockerCli.Out(), "Insecure Registries:")
		for _, registry := range info.RegistryConfig.IndexConfigs {
			if registry.Secure == false {
				fmt.Fprintf(dockerCli.Out(), " %s\n", registry.Name)
			}
		}

		for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs {
			mask, _ := registry.Mask.Size()
			fmt.Fprintf(dockerCli.Out(), " %s/%d\n", registry.IP.String(), mask)
		}
	}

	if info.RegistryConfig != nil && len(info.RegistryConfig.Mirrors) > 0 {
		fmt.Fprintln(dockerCli.Out(), "Registry Mirrors:")
		for _, mirror := range info.RegistryConfig.Mirrors {
			fmt.Fprintf(dockerCli.Out(), " %s\n", mirror)
		}
	}

	fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n", info.LiveRestoreEnabled)

	return nil
}

func formatInfo(dockerCli *command.DockerCli, info types.Info, format string) error {
	tmpl, err := templates.Parse(format)
	if err != nil {
		return cli.StatusError{StatusCode: 64,
			Status: "Template parsing error: " + err.Error()}
	}
	err = tmpl.Execute(dockerCli.Out(), info)
	dockerCli.Out().Write([]byte{'\n'})
	return err
}
<commit_msg>Remove duplicate keys in labels of `docker info`<commit_after>package system

import (
	"fmt"
	"strings"
	"time"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/utils/templates"
	"github.com/docker/go-units"
	"github.com/spf13/cobra"
)

type infoOptions struct {
	format string
}

// NewInfoCommand creates a new cobra.Command for `docker info`
func NewInfoCommand(dockerCli *command.DockerCli) *cobra.Command {
	var opts infoOptions

	cmd := &cobra.Command{
		Use:   "info [OPTIONS]",
		Short: "Display system-wide information",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runInfo(dockerCli, &opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")

	return cmd
}

func runInfo(dockerCli *command.DockerCli, opts *infoOptions) error {
	ctx := context.Background()
	info, err := dockerCli.Client().Info(ctx)
	if err != nil {
		return err
	}
	if opts.format == "" {
		return prettyPrintInfo(dockerCli, info)
	}
	return formatInfo(dockerCli, info, opts.format)
}

func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
	fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers)
	fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning)
	fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused)
	fmt.Fprintf(dockerCli.Out(), " Stopped: %d\n", info.ContainersStopped)
	fmt.Fprintf(dockerCli.Out(), "Images: %d\n", info.Images)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Server Version: %s\n", info.ServerVersion)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Storage Driver: %s\n", info.Driver)
	if info.DriverStatus != nil {
		for _, pair := range info.DriverStatus {
			fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1])

			// print a warning if devicemapper is using a loopback file
			if pair[0] == "Data loop file" {
				fmt.Fprintln(dockerCli.Err(), " WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.")
			}
		}

	}
	if info.SystemStatus != nil {
		for _, pair := range info.SystemStatus {
			fmt.Fprintf(dockerCli.Out(), "%s: %s\n", pair[0], pair[1])
		}
	}
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver)

	fmt.Fprintf(dockerCli.Out(), "Plugins: \n")
	fmt.Fprintf(dockerCli.Out(), " Volume:")
	fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " "))
	fmt.Fprintf(dockerCli.Out(), "\n")
	fmt.Fprintf(dockerCli.Out(), " Network:")
	fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Network, " "))
	fmt.Fprintf(dockerCli.Out(), "\n")

	if len(info.Plugins.Authorization) != 0 {
		fmt.Fprintf(dockerCli.Out(), " Authorization:")
		fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Authorization, " "))
		fmt.Fprintf(dockerCli.Out(), "\n")
	}

	fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState)
	if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive {
		fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID)
		if info.Swarm.Error != "" {
			fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error)
		}
		fmt.Fprintf(dockerCli.Out(), " Is Manager: %v\n", info.Swarm.ControlAvailable)
		if info.Swarm.ControlAvailable {
			fmt.Fprintf(dockerCli.Out(), " ClusterID: %s\n", info.Swarm.Cluster.ID)
			fmt.Fprintf(dockerCli.Out(), " Managers: %d\n", info.Swarm.Managers)
			fmt.Fprintf(dockerCli.Out(), " Nodes: %d\n", info.Swarm.Nodes)
			fmt.Fprintf(dockerCli.Out(), " Orchestration:\n")
			taskHistoryRetentionLimit := int64(0)
			if info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit != nil {
				taskHistoryRetentionLimit = *info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit
			}
			fmt.Fprintf(dockerCli.Out(), "  Task History Retention Limit: %d\n", taskHistoryRetentionLimit)
			fmt.Fprintf(dockerCli.Out(), " Raft:\n")
			fmt.Fprintf(dockerCli.Out(), "  Snapshot Interval: %d\n", info.Swarm.Cluster.Spec.Raft.SnapshotInterval)
			fmt.Fprintf(dockerCli.Out(), "  Heartbeat Tick: %d\n", info.Swarm.Cluster.Spec.Raft.HeartbeatTick)
			fmt.Fprintf(dockerCli.Out(), "  Election Tick: %d\n", info.Swarm.Cluster.Spec.Raft.ElectionTick)
			fmt.Fprintf(dockerCli.Out(), " Dispatcher:\n")
			fmt.Fprintf(dockerCli.Out(), "  Heartbeat Period: %s\n", units.HumanDuration(time.Duration(info.Swarm.Cluster.Spec.Dispatcher.HeartbeatPeriod)))
			fmt.Fprintf(dockerCli.Out(), " CA Configuration:\n")
			fmt.Fprintf(dockerCli.Out(), "  Expiry Duration: %s\n", units.HumanDuration(info.Swarm.Cluster.Spec.CAConfig.NodeCertExpiry))
			if len(info.Swarm.Cluster.Spec.CAConfig.ExternalCAs) > 0 {
				fmt.Fprintf(dockerCli.Out(), "  External CAs:\n")
				for _, entry := range info.Swarm.Cluster.Spec.CAConfig.ExternalCAs {
					fmt.Fprintf(dockerCli.Out(), "    %s: %s\n", entry.Protocol, entry.URL)
				}
			}
		}
		fmt.Fprintf(dockerCli.Out(), " Node Address: %s\n", info.Swarm.NodeAddr)
	}

	if len(info.Runtimes) > 0 {
		fmt.Fprintf(dockerCli.Out(), "Runtimes:")
		for name := range info.Runtimes {
			fmt.Fprintf(dockerCli.Out(), " %s", name)
		}
		fmt.Fprint(dockerCli.Out(), "\n")
		fmt.Fprintf(dockerCli.Out(), "Default Runtime: %s\n", info.DefaultRuntime)
	}

	if info.OSType == "linux" {
		fmt.Fprintf(dockerCli.Out(), "Security Options:")
		ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " "))
		fmt.Fprintf(dockerCli.Out(), "\n")
	}

	// Isolation only has meaning on a Windows daemon.
	if info.OSType == "windows" {
		fmt.Fprintf(dockerCli.Out(), "Default Isolation: %v\n", info.Isolation)
	}

	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Kernel Version: %s\n", info.KernelVersion)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Operating System: %s\n", info.OperatingSystem)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "OSType: %s\n", info.OSType)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Architecture: %s\n", info.Architecture)
	fmt.Fprintf(dockerCli.Out(), "CPUs: %d\n", info.NCPU)
	fmt.Fprintf(dockerCli.Out(), "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Name: %s\n", info.Name)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "ID: %s\n", info.ID)
	fmt.Fprintf(dockerCli.Out(), "Docker Root Dir: %s\n", info.DockerRootDir)
	fmt.Fprintf(dockerCli.Out(), "Debug Mode (client): %v\n", utils.IsDebugEnabled())
	fmt.Fprintf(dockerCli.Out(), "Debug Mode (server): %v\n", info.Debug)

	if info.Debug {
		fmt.Fprintf(dockerCli.Out(), " File Descriptors: %d\n", info.NFd)
		fmt.Fprintf(dockerCli.Out(), " Goroutines: %d\n", info.NGoroutines)
		fmt.Fprintf(dockerCli.Out(), " System Time: %s\n", info.SystemTime)
		fmt.Fprintf(dockerCli.Out(), " EventsListeners: %d\n", info.NEventsListener)
	}

	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Http Proxy: %s\n", info.HTTPProxy)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Https Proxy: %s\n", info.HTTPSProxy)
	ioutils.FprintfIfNotEmpty(dockerCli.Out(), "No Proxy: %s\n", info.NoProxy)

	if info.IndexServerAddress != "" {
		u := dockerCli.ConfigFile().AuthConfigs[info.IndexServerAddress].Username
		if len(u) > 0 {
			fmt.Fprintf(dockerCli.Out(), "Username: %v\n", u)
		}
		fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress)
	}

	// Only output these warnings if the server does not support these features
	if info.OSType != "windows" {
		if !info.MemoryLimit {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support")
		}
		if !info.SwapLimit {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support")
		}
		if !info.KernelMemory {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support")
		}
		if !info.OomKillDisable {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support")
		}
		if !info.CPUCfsQuota {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support")
		}
		if !info.CPUCfsPeriod {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support")
		}
		if !info.CPUShares {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support")
		}
		if !info.CPUSet {
			fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support")
		}
		if !info.IPv4Forwarding {
			fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled")
		}
		if !info.BridgeNfIptables {
			fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled")
		}
		if !info.BridgeNfIP6tables {
			fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled")
		}
	}

	if info.Labels != nil {
		fmt.Fprintln(dockerCli.Out(), "Labels:")
		for _, attribute := range info.Labels {
			fmt.Fprintf(dockerCli.Out(), " %s\n", attribute)
		}
		// TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out
		// after 3 release cycles (1.16). For now, a WARNING will be generated. The following will
		// be removed eventually.
		labelMap := map[string]string{}
		for _, label := range info.Labels {
			stringSlice := strings.SplitN(label, "=", 2)
			if len(stringSlice) > 1 {
				// If there is a conflict we will throw out an warning
				if v, ok := labelMap[stringSlice[0]]; ok && v != stringSlice[1] {
					fmt.Fprintln(dockerCli.Err(), "WARNING: labels with duplicate keys and conflicting values have been deprecated")
					break
				}
				labelMap[stringSlice[0]] = stringSlice[1]
			}
		}
	}

	ioutils.FprintfIfTrue(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild)
	if info.ClusterStore != "" {
		fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore)
	}

	if info.ClusterAdvertise != "" {
		fmt.Fprintf(dockerCli.Out(), "Cluster Advertise: %s\n", info.ClusterAdvertise)
	}

	if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) {
		fmt.Fprintln(dockerCli.Out(), "Insecure Registries:")
		for _, registry := range info.RegistryConfig.IndexConfigs {
			if registry.Secure == false {
				fmt.Fprintf(dockerCli.Out(), " %s\n", registry.Name)
			}
		}

		for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs {
			mask, _ := registry.Mask.Size()
			fmt.Fprintf(dockerCli.Out(), " %s/%d\n", registry.IP.String(), mask)
		}
	}

	if info.RegistryConfig != nil && len(info.RegistryConfig.Mirrors) > 0 {
		fmt.Fprintln(dockerCli.Out(), "Registry Mirrors:")
		for _, mirror := range info.RegistryConfig.Mirrors {
			fmt.Fprintf(dockerCli.Out(), " %s\n", mirror)
		}
	}

	fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n", info.LiveRestoreEnabled)

	return nil
}

func formatInfo(dockerCli *command.DockerCli, info types.Info, format string) error {
	tmpl, err := templates.Parse(format)
	if err != nil {
		return cli.StatusError{StatusCode: 64,
			Status: "Template parsing error: " + err.Error()}
	}
	err = tmpl.Execute(dockerCli.Out(), info)
	dockerCli.Out().Write([]byte{'\n'})
	return err
}
<|endoftext|>


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

package command

import (
	"fmt"
	"strings"

	v3 "github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/pkg/types"
)

type simplePrinter struct {
	isHex     bool
	valueOnly bool
}

func (s *simplePrinter) Del(resp v3.DeleteResponse) {
	fmt.Println(resp.Deleted)
	for _, kv := range resp.PrevKvs {
		printKV(s.isHex, s.valueOnly, kv)
	}
}

func (s *simplePrinter) Get(resp v3.GetResponse) {
	for _, kv := range resp.Kvs {
		printKV(s.isHex, s.valueOnly, kv)
	}
}

func (s *simplePrinter) Put(r v3.PutResponse) {
	fmt.Println("OK")
	if r.PrevKv != nil {
		printKV(s.isHex, s.valueOnly, r.PrevKv)
	}
}

func (s *simplePrinter) Txn(resp v3.TxnResponse) {
	if resp.Succeeded {
		fmt.Println("SUCCESS")
	} else {
		fmt.Println("FAILURE")
	}

	for _, r := range resp.Responses {
		fmt.Println("")
		switch v := r.Response.(type) {
		case *pb.ResponseOp_ResponseDeleteRange:
			s.Del((v3.DeleteResponse)(*v.ResponseDeleteRange))
		case *pb.ResponseOp_ResponsePut:
			s.Put((v3.PutResponse)(*v.ResponsePut))
		case *pb.ResponseOp_ResponseRange:
			s.Get(((v3.GetResponse)(*v.ResponseRange)))
		default:
			fmt.Printf("unexpected response %+v\n", r)
		}
	}
}

func (s *simplePrinter) Watch(resp v3.WatchResponse) {
	for _, e := range resp.Events {
		fmt.Println(e.Type)
		if e.PrevKv != nil {
			printKV(s.isHex, s.valueOnly, e.PrevKv)
		}
		printKV(s.isHex, s.valueOnly, e.Kv)
	}
}

func (s *simplePrinter) Grant(resp v3.LeaseGrantResponse) {
	fmt.Printf("lease %016x granted with TTL(%ds)\n", resp.ID, resp.TTL)
}

func (p *simplePrinter) Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse) {
	fmt.Printf("lease %016x revoked\n", id)
}

func (p *simplePrinter) KeepAlive(resp v3.LeaseKeepAliveResponse) {
	fmt.Printf("lease %016x keepalived with TTL(%d)\n", resp.ID, resp.TTL)
}

func (s *simplePrinter) TimeToLive(resp v3.LeaseTimeToLiveResponse, keys bool) {
	txt := fmt.Sprintf("lease %016x granted with TTL(%ds), remaining(%ds)", resp.ID, resp.GrantedTTL, resp.TTL)
	if keys {
		ks := make([]string, len(resp.Keys))
		for i := range resp.Keys {
			ks[i] = string(resp.Keys[i])
		}
		txt += fmt.Sprintf(", attached keys(%v)", ks)
	}
	fmt.Println(txt)
}

func (s *simplePrinter) Leases(resp v3.LeaseLeasesResponse) {
	fmt.Printf("found %d leases\n", len(resp.Leases))
	for _, item := range resp.Leases {
		fmt.Printf("%016x\n", item.ID)
	}
}

func (s *simplePrinter) Alarm(resp v3.AlarmResponse) {
	for _, e := range resp.Alarms {
		fmt.Printf("%+v\n", e)
	}
}

func (s *simplePrinter) MemberAdd(r v3.MemberAddResponse) {
	fmt.Printf("Member %16x added to cluster %16x\n", r.Member.ID, r.Header.ClusterId)
}

func (s *simplePrinter) MemberRemove(id uint64, r v3.MemberRemoveResponse) {
	fmt.Printf("Member %16x removed from cluster %16x\n", id, r.Header.ClusterId)
}

func (s *simplePrinter) MemberUpdate(id uint64, r v3.MemberUpdateResponse) {
	fmt.Printf("Member %16x updated in cluster %16x\n", id, r.Header.ClusterId)
}

func (s *simplePrinter) MemberList(resp v3.MemberListResponse) {
	_, rows := makeMemberListTable(resp)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
	_, rows := makeEndpointStatusTable(statusList)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) EndpointHashKV(hashList []epHashKV) {
	_, rows := makeEndpointHashKVTable(hashList)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) DBStatus(ds dbstatus) {
	_, rows := makeDBStatusTable(ds)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) MoveLeader(leader, target uint64, r v3.MoveLeaderResponse) {
	fmt.Printf("Leadership transferred from %s to %s\n", types.ID(leader), types.ID(target))
}

func (s *simplePrinter) RoleAdd(role string, r v3.AuthRoleAddResponse) {
	fmt.Printf("Role %s created\n", role)
}

func (s *simplePrinter) RoleGet(role string, r v3.AuthRoleGetResponse) {
	fmt.Printf("Role %s\n", role)
	fmt.Println("KV Read:")

	printRange := func(perm *v3.Permission) {
		sKey := string(perm.Key)
		sRangeEnd := string(perm.RangeEnd)
		if strings.Compare(sRangeEnd, "\x00") != 0 {
			fmt.Printf("\t[%s, %s)", sKey, sRangeEnd)
		} else {
			fmt.Printf("\t[%s, <open ended>", sKey)
		}
		if strings.Compare(v3.GetPrefixRangeEnd(sKey), sRangeEnd) == 0 {
			fmt.Printf(" (prefix %s)", sKey)
		}
		fmt.Printf("\n")
	}

	for _, perm := range r.Perm {
		if perm.PermType == v3.PermRead || perm.PermType == v3.PermReadWrite {
			if len(perm.RangeEnd) == 0 {
				fmt.Printf("\t%s\n", string(perm.Key))
			} else {
				printRange((*v3.Permission)(perm))
			}
		}
	}
	fmt.Println("KV Write:")
	for _, perm := range r.Perm {
		if perm.PermType == v3.PermWrite || perm.PermType == v3.PermReadWrite {
			if len(perm.RangeEnd) == 0 {
				fmt.Printf("\t%s\n", string(perm.Key))
			} else {
				printRange((*v3.Permission)(perm))
			}
		}
	}
}

func (s *simplePrinter) RoleList(r v3.AuthRoleListResponse) {
	for _, role := range r.Roles {
		fmt.Printf("%s\n", role)
	}
}

func (s *simplePrinter) RoleDelete(role string, r v3.AuthRoleDeleteResponse) {
	fmt.Printf("Role %s deleted\n", role)
}

func (s *simplePrinter) RoleGrantPermission(role string, r v3.AuthRoleGrantPermissionResponse) {
	fmt.Printf("Role %s updated\n", role)
}

func (s *simplePrinter) RoleRevokePermission(role string, key string, end string, r v3.AuthRoleRevokePermissionResponse) {
	if len(end) == 0 {
		fmt.Printf("Permission of key %s is revoked from role %s\n", key, role)
		return
	}
	if strings.Compare(end, "\x00") != 0 {
		fmt.Printf("Permission of range [%s, %s) is revoked from role %s\n", key, end, role)
	} else {
		fmt.Printf("Permission of range [%s, <open ended> is revoked from role %s\n", key, role)
	}
}

func (s *simplePrinter) UserAdd(name string, r v3.AuthUserAddResponse) {
	fmt.Printf("User %s created\n", name)
}

func (s *simplePrinter) UserGet(name string, r v3.AuthUserGetResponse) {
	fmt.Printf("User: %s\n", name)
	fmt.Printf("Roles:")
	for _, role := range r.Roles {
		fmt.Printf(" %s", role)
	}
	fmt.Printf("\n")
}

func (s *simplePrinter) UserChangePassword(v3.AuthUserChangePasswordResponse) {
	fmt.Println("Password updated")
}

func (s *simplePrinter) UserGrantRole(user string, role string, r v3.AuthUserGrantRoleResponse) {
	fmt.Printf("Role %s is granted to user %s\n", role, user)
}

func (s *simplePrinter) UserRevokeRole(user string, role string, r v3.AuthUserRevokeRoleResponse) {
	fmt.Printf("Role %s is revoked from user %s\n", role, user)
}

func (s *simplePrinter) UserDelete(user string, r v3.AuthUserDeleteResponse) {
	fmt.Printf("User %s deleted\n", user)
}

func (s *simplePrinter) UserList(r v3.AuthUserListResponse) {
	for _, user := range r.Users {
		fmt.Printf("%s\n", user)
	}
}
<commit_msg>etcdctl/ctlv3: clarify "lease timetolive" output on expired lease<commit_after>// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"fmt"
	"strings"

	v3 "github.com/coreos/etcd/clientv3"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/pkg/types"
)

type simplePrinter struct {
	isHex     bool
	valueOnly bool
}

func (s *simplePrinter) Del(resp v3.DeleteResponse) {
	fmt.Println(resp.Deleted)
	for _, kv := range resp.PrevKvs {
		printKV(s.isHex, s.valueOnly, kv)
	}
}

func (s *simplePrinter) Get(resp v3.GetResponse) {
	for _, kv := range resp.Kvs {
		printKV(s.isHex, s.valueOnly, kv)
	}
}

func (s *simplePrinter) Put(r v3.PutResponse) {
	fmt.Println("OK")
	if r.PrevKv != nil {
		printKV(s.isHex, s.valueOnly, r.PrevKv)
	}
}

func (s *simplePrinter) Txn(resp v3.TxnResponse) {
	if resp.Succeeded {
		fmt.Println("SUCCESS")
	} else {
		fmt.Println("FAILURE")
	}

	for _, r := range resp.Responses {
		fmt.Println("")
		switch v := r.Response.(type) {
		case *pb.ResponseOp_ResponseDeleteRange:
			s.Del((v3.DeleteResponse)(*v.ResponseDeleteRange))
		case *pb.ResponseOp_ResponsePut:
			s.Put((v3.PutResponse)(*v.ResponsePut))
		case *pb.ResponseOp_ResponseRange:
			s.Get(((v3.GetResponse)(*v.ResponseRange)))
		default:
			fmt.Printf("unexpected response %+v\n", r)
		}
	}
}

func (s *simplePrinter) Watch(resp v3.WatchResponse) {
	for _, e := range resp.Events {
		fmt.Println(e.Type)
		if e.PrevKv != nil {
			printKV(s.isHex, s.valueOnly, e.PrevKv)
		}
		printKV(s.isHex, s.valueOnly, e.Kv)
	}
}

func (s *simplePrinter) Grant(resp v3.LeaseGrantResponse) {
	fmt.Printf("lease %016x granted with TTL(%ds)\n", resp.ID, resp.TTL)
}

func (p *simplePrinter) Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse) {
	fmt.Printf("lease %016x revoked\n", id)
}

func (p *simplePrinter) KeepAlive(resp v3.LeaseKeepAliveResponse) {
	fmt.Printf("lease %016x keepalived with TTL(%d)\n", resp.ID, resp.TTL)
}

func (s *simplePrinter) TimeToLive(resp v3.LeaseTimeToLiveResponse, keys bool) {
	if resp.GrantedTTL == 0 && resp.TTL == -1 {
		fmt.Printf("lease %016x already expired\n", resp.ID)
		return
	}

	txt := fmt.Sprintf("lease %016x granted with TTL(%ds), remaining(%ds)", resp.ID, resp.GrantedTTL, resp.TTL)
	if keys {
		ks := make([]string, len(resp.Keys))
		for i := range resp.Keys {
			ks[i] = string(resp.Keys[i])
		}
		txt += fmt.Sprintf(", attached keys(%v)", ks)
	}
	fmt.Println(txt)
}

func (s *simplePrinter) Leases(resp v3.LeaseLeasesResponse) {
	fmt.Printf("found %d leases\n", len(resp.Leases))
	for _, item := range resp.Leases {
		fmt.Printf("%016x\n", item.ID)
	}
}

func (s *simplePrinter) Alarm(resp v3.AlarmResponse) {
	for _, e := range resp.Alarms {
		fmt.Printf("%+v\n", e)
	}
}

func (s *simplePrinter) MemberAdd(r v3.MemberAddResponse) {
	fmt.Printf("Member %16x added to cluster %16x\n", r.Member.ID, r.Header.ClusterId)
}

func (s *simplePrinter) MemberRemove(id uint64, r v3.MemberRemoveResponse) {
	fmt.Printf("Member %16x removed from cluster %16x\n", id, r.Header.ClusterId)
}

func (s *simplePrinter) MemberUpdate(id uint64, r v3.MemberUpdateResponse) {
	fmt.Printf("Member %16x updated in cluster %16x\n", id, r.Header.ClusterId)
}

func (s *simplePrinter) MemberList(resp v3.MemberListResponse) {
	_, rows := makeMemberListTable(resp)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
	_, rows := makeEndpointStatusTable(statusList)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) EndpointHashKV(hashList []epHashKV) {
	_, rows := makeEndpointHashKVTable(hashList)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) DBStatus(ds dbstatus) {
	_, rows := makeDBStatusTable(ds)
	for _, row := range rows {
		fmt.Println(strings.Join(row, ", "))
	}
}

func (s *simplePrinter) MoveLeader(leader, target uint64, r v3.MoveLeaderResponse) {
	fmt.Printf("Leadership transferred from %s to %s\n", types.ID(leader), types.ID(target))
}

func (s *simplePrinter) RoleAdd(role string, r v3.AuthRoleAddResponse) {
	fmt.Printf("Role %s created\n", role)
}

func (s *simplePrinter) RoleGet(role string, r v3.AuthRoleGetResponse) {
	fmt.Printf("Role %s\n", role)
	fmt.Println("KV Read:")

	printRange := func(perm *v3.Permission) {
		sKey := string(perm.Key)
		sRangeEnd := string(perm.RangeEnd)
		if strings.Compare(sRangeEnd, "\x00") != 0 {
			fmt.Printf("\t[%s, %s)", sKey, sRangeEnd)
		} else {
			fmt.Printf("\t[%s, <open ended>", sKey)
		}
		if strings.Compare(v3.GetPrefixRangeEnd(sKey), sRangeEnd) == 0 {
			fmt.Printf(" (prefix %s)", sKey)
		}
		fmt.Printf("\n")
	}

	for _, perm := range r.Perm {
		if perm.PermType == v3.PermRead || perm.PermType == v3.PermReadWrite {
			if len(perm.RangeEnd) == 0 {
				fmt.Printf("\t%s\n", string(perm.Key))
			} else {
				printRange((*v3.Permission)(perm))
			}
		}
	}
	fmt.Println("KV Write:")
	for _, perm := range r.Perm {
		if perm.PermType == v3.PermWrite || perm.PermType == v3.PermReadWrite {
			if len(perm.RangeEnd) == 0 {
				fmt.Printf("\t%s\n", string(perm.Key))
			} else {
				printRange((*v3.Permission)(perm))
			}
		}
	}
}

func (s *simplePrinter) RoleList(r v3.AuthRoleListResponse) {
	for _, role := range r.Roles {
		fmt.Printf("%s\n", role)
	}
}

func (s *simplePrinter) RoleDelete(role string, r v3.AuthRoleDeleteResponse) {
	fmt.Printf("Role %s deleted\n", role)
}

func (s *simplePrinter) RoleGrantPermission(role string, r v3.AuthRoleGrantPermissionResponse) {
	fmt.Printf("Role %s updated\n", role)
}

func (s *simplePrinter) RoleRevokePermission(role string, key string, end string, r v3.AuthRoleRevokePermissionResponse) {
	if len(end) == 0 {
		fmt.Printf("Permission of key %s is revoked from role %s\n", key, role)
		return
	}
	if strings.Compare(end, "\x00") != 0 {
		fmt.Printf("Permission of range [%s, %s) is revoked from role %s\n", key, end, role)
	} else {
		fmt.Printf("Permission of range [%s, <open ended> is revoked from role %s\n", key, role)
	}
}

func (s *simplePrinter) UserAdd(name string, r v3.AuthUserAddResponse) {
	fmt.Printf("User %s created\n", name)
}

func (s *simplePrinter) UserGet(name string, r v3.AuthUserGetResponse) {
	fmt.Printf("User: %s\n", name)
	fmt.Printf("Roles:")
	for _, role := range r.Roles {
		fmt.Printf(" %s", role)
	}
	fmt.Printf("\n")
}

func (s *simplePrinter) UserChangePassword(v3.AuthUserChangePasswordResponse) {
	fmt.Println("Password updated")
}

func (s *simplePrinter) UserGrantRole(user string, role string, r v3.AuthUserGrantRoleResponse) {
	fmt.Printf("Role %s is granted to user %s\n", role, user)
}

func (s *simplePrinter) UserRevokeRole(user string, role string, r v3.AuthUserRevokeRoleResponse) {
	fmt.Printf("Role %s is revoked from user %s\n", role, user)
}

func (s *simplePrinter) UserDelete(user string, r v3.AuthUserDeleteResponse) {
	fmt.Printf("User %s deleted\n", user)
}

func (s *simplePrinter) UserList(r v3.AuthUserListResponse) {
	for _, user := range r.Users {
		fmt.Printf("%s\n", user)
	}
}
<|endoftext|>


<commit_before>package geth

import (
	"fmt"
	"github.com/SmartPool/smartpool-client"
	"github.com/SmartPool/smartpool-client/ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
	"os"
)

type EthashContractClient struct {
	contract   *Ethash
	transactor *bind.TransactOpts
	node       ethereum.RPCClient
	sender     common.Address
}

func (cc *EthashContractClient) SetEpochData(
	epoch *big.Int,
	fullSizeIn128Resolution *big.Int,
	branchDepth *big.Int,
	merkleNodes []*big.Int) error {

	nodes := []*big.Int{}
	start := big.NewInt(0)
	fmt.Printf("No meaningful nodes: %d\n", len(merkleNodes))
	for k, n := range merkleNodes {
		nodes = append(nodes, n)
		if len(nodes) == 40 || k == len(merkleNodes)-1 {
			mnlen := big.NewInt(int64(len(nodes)))
			blockNo, err := cc.node.BlockNumber()
			blockNo.Add(blockNo, big.NewInt(1))
			if err != nil {
				smartpool.Output.Printf("Setting epoch data. Error: %s\n", err)
				return err
			}
			fmt.Printf("Going to do tx\n")
			fmt.Printf("Block Number: %d\n", blockNo.Int64())
			tx, err := cc.contract.SetEpochData(
				cc.transactor, epoch, fullSizeIn128Resolution,
				branchDepth, nodes, start, mnlen)
			if err != nil {
				smartpool.Output.Printf("Setting optimized epoch data. Error: %s\n", err)
				return err
			}
			errCode, errInfo, err := NewTxWatcher(
				tx, cc.node, blockNo, SetEpochDataEventTopic,
				cc.sender.Big()).Wait()
			if err != nil {
				smartpool.Output.Printf("Tx: %s was not approved by the network in time.\n", tx.Hash().Hex())
				return err
			}
			if errCode.Cmp(common.Big0) != 0 {
				smartpool.Output.Printf("Error code: 0x%s - Error info: 0x%s\n", errCode.Text(16), errInfo.Text(16))
				// return errors.New(ErrorMsg(errCode, errInfo))
			}
			start.Add(start, mnlen)
			nodes = []*big.Int{}
		}
	}
	return nil
}

func NewEthashContractClient(
	contractAddr common.Address, node ethereum.RPCClient, miner common.Address,
	ipc, keystorePath, passphrase string, gasprice uint64) (*EthashContractClient, error) {
	client, err := getClient(ipc)
	if err != nil {
		smartpool.Output.Printf("Couldn't connect to Geth/Parity. Error: %s\n", err)
		return nil, err
	}
	ethash, err := NewEthash(contractAddr, client)
	if err != nil {
		smartpool.Output.Printf("Couldn't get SmartPool information from Ethereum Blockchain. Error: %s\n", err)
		return nil, err
	}
	account := GetAccount(keystorePath, miner, passphrase)
	if account == nil {
		smartpool.Output.Printf("Couldn't get any account from key store.\n")
		return nil, err
	}
	keyio, err := os.Open(account.KeyFile())
	if err != nil {
		smartpool.Output.Printf("Failed to open key file: %s\n", err)
		return nil, err
	}
	smartpool.Output.Printf("Unlocking account...")
	auth, err := bind.NewTransactor(keyio, account.PassPhrase())
	if err != nil {
		smartpool.Output.Printf("Failed to create authorized transactor: %s\n", err)
		return nil, err
	}
	if gasprice != 0 {
		auth.GasPrice = big.NewInt(int64(gasprice * 1000000000))
		smartpool.Output.Printf("Gas price is set to: %s wei.\n", auth.GasPrice.Text(10))
	}
	smartpool.Output.Printf("Done.\n")
	return &EthashContractClient{ethash, auth, node, miner}, nil
}
<commit_msg>keep setting epoch data if previous tx has problem<commit_after>package geth

import (
	"fmt"
	"github.com/SmartPool/smartpool-client"
	"github.com/SmartPool/smartpool-client/ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
	"os"
)

type EthashContractClient struct {
	contract   *Ethash
	transactor *bind.TransactOpts
	node       ethereum.RPCClient
	sender     common.Address
}

func (cc *EthashContractClient) SetEpochData(
	epoch *big.Int,
	fullSizeIn128Resolution *big.Int,
	branchDepth *big.Int,
	merkleNodes []*big.Int) error {

	nodes := []*big.Int{}
	start := big.NewInt(0)
	fmt.Printf("No meaningful nodes: %d\n", len(merkleNodes))
	for k, n := range merkleNodes {
		nodes = append(nodes, n)
		if len(nodes) == 40 || k == len(merkleNodes)-1 {
			mnlen := big.NewInt(int64(len(nodes)))
			blockNo, err := cc.node.BlockNumber()
			blockNo.Add(blockNo, big.NewInt(1))
			if err != nil {
				smartpool.Output.Printf("Setting epoch data. Error: %s\n", err)
				return err
			}
			fmt.Printf("Going to do tx\n")
			fmt.Printf("Block Number: %d\n", blockNo.Int64())
			tx, err := cc.contract.SetEpochData(
				cc.transactor, epoch, fullSizeIn128Resolution,
				branchDepth, nodes, start, mnlen)
			if err != nil {
				smartpool.Output.Printf("Setting optimized epoch data. Error: %s\n", err)
				return err
			}
			errCode, errInfo, err := NewTxWatcher(
				tx, cc.node, blockNo, SetEpochDataEventTopic,
				cc.sender.Big()).WaitAndRetry()
			if err != nil {
				smartpool.Output.Printf("Tx: %s was not approved by the network in time.\n", tx.Hash().Hex())
				start.Add(start, mnlen)
				nodes = []*big.Int{}
				continue
			}
			if errCode.Cmp(common.Big0) != 0 {
				smartpool.Output.Printf("Error code: 0x%s - Error info: 0x%s\n", errCode.Text(16), errInfo.Text(16))
				// return errors.New(ErrorMsg(errCode, errInfo))
			}
			start.Add(start, mnlen)
			nodes = []*big.Int{}
		}
	}
	return nil
}

func NewEthashContractClient(
	contractAddr common.Address, node ethereum.RPCClient, miner common.Address,
	ipc, keystorePath, passphrase string, gasprice uint64) (*EthashContractClient, error) {
	client, err := getClient(ipc)
	if err != nil {
		smartpool.Output.Printf("Couldn't connect to Geth/Parity. Error: %s\n", err)
		return nil, err
	}
	ethash, err := NewEthash(contractAddr, client)
	if err != nil {
		smartpool.Output.Printf("Couldn't get SmartPool information from Ethereum Blockchain. Error: %s\n", err)
		return nil, err
	}
	account := GetAccount(keystorePath, miner, passphrase)
	if account == nil {
		smartpool.Output.Printf("Couldn't get any account from key store.\n")
		return nil, err
	}
	keyio, err := os.Open(account.KeyFile())
	if err != nil {
		smartpool.Output.Printf("Failed to open key file: %s\n", err)
		return nil, err
	}
	smartpool.Output.Printf("Unlocking account...")
	auth, err := bind.NewTransactor(keyio, account.PassPhrase())
	if err != nil {
		smartpool.Output.Printf("Failed to create authorized transactor: %s\n", err)
		return nil, err
	}
	if gasprice != 0 {
		auth.GasPrice = big.NewInt(int64(gasprice * 1000000000))
		smartpool.Output.Printf("Gas price is set to: %s wei.\n", auth.GasPrice.Text(10))
	}
	smartpool.Output.Printf("Done.\n")
	return &EthashContractClient{ethash, auth, node, miner}, nil
}
<|endoftext|>


<commit_before>package quobyte

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"strconv"
)

const (
	emptyResponse string = "Empty result and no error occured"
)

type request struct {
	ID      string      `json:"id"`
	Version string      `json:"jsonrpc"`
	Method  string      `json:"method"`
	Params  interface{} `json:"params"`
}

type response struct {
	ID      string           `json:"id"`
	Version string           `json:"jsonrpc"`
	Result  *json.RawMessage `json:"result"`
	Error   *json.RawMessage `json:"error"`
}

type rpcError struct {
	Code    int64  `json:"code"`
	Message string `json:"message"`
}

func (err *rpcError) decodeErrorCode() string {
	switch err.Code {
	case -32600:
		return "ERROR_CODE_INVALID_REQUEST"
	case -32603:
		return "ERROR_CODE_JSON_ENCODING_FAILED"
	case -32601:
		return "ERROR_CODE_METHOD_NOT_FOUND"
	case -32700:
		return "ERROR_CODE_PARSE_ERROR"
	}

	return ""
}

func encodeRequest(method string, params interface{}) ([]byte, error) {
	return json.Marshal(&request{
		// Generate random ID and convert it to a string
		ID:      strconv.FormatInt(rand.Int63(), 10),
		Version: "2.0",
		Method:  method,
		Params:  params,
	})
}

func decodeResponse(ioReader io.Reader, reply interface{}) error {
	var resp response
	if err := json.NewDecoder(ioReader).Decode(&resp); err != nil {
		return err
	}

	if resp.Error != nil {
		var rpcErr rpcError
		if err := json.Unmarshal(*resp.Error, &rpcErr); err != nil {
			return err
		}

		if rpcErr.Message != "" {
			return errors.New(rpcErr.Message)
		}

		respError := rpcErr.decodeErrorCode()
		if respError != "" {
			return errors.New(respError)
		}
	}

	if resp.Result != nil && reply != nil {
		return json.Unmarshal(*resp.Result, reply)
	}

	return errors.New(emptyResponse)
}

func (client QuobyteClient) sendRequest(method string, request interface{}, response interface{}) error {
	message, err := encodeRequest(method, request)
	if err != nil {
		return err
	}
	fmt.Printf("Sending JsonRPC message: %[1]s \n", message)
	req, err := http.NewRequest("POST", client.url, bytes.NewBuffer(message))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.SetBasicAuth(client.username, client.password)
	resp, err := client.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return decodeResponse(resp.Body, &response)
}
<commit_msg>Bumps the API client version to v0.1.1<commit_after>package quobyte

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"strconv"
)

const (
	emptyResponse string = "Empty result and no error occured"
)

type request struct {
	ID      string      `json:"id"`
	Version string      `json:"jsonrpc"`
	Method  string      `json:"method"`
	Params  interface{} `json:"params"`
}

type response struct {
	ID      string           `json:"id"`
	Version string           `json:"jsonrpc"`
	Result  *json.RawMessage `json:"result"`
	Error   *json.RawMessage `json:"error"`
}

type rpcError struct {
	Code    int64  `json:"code"`
	Message string `json:"message"`
}

func (err *rpcError) decodeErrorCode() string {
	switch err.Code {
	case -32600:
		return "ERROR_CODE_INVALID_REQUEST"
	case -32603:
		return "ERROR_CODE_JSON_ENCODING_FAILED"
	case -32601:
		return "ERROR_CODE_METHOD_NOT_FOUND"
	case -32700:
		return "ERROR_CODE_PARSE_ERROR"
	}

	return ""
}

func encodeRequest(method string, params interface{}) ([]byte, error) {
	return json.Marshal(&request{
		// Generate random ID and convert it to a string
		ID:      strconv.FormatInt(rand.Int63(), 10),
		Version: "2.0",
		Method:  method,
		Params:  params,
	})
}

func decodeResponse(ioReader io.Reader, reply interface{}) error {
	var resp response
	if err := json.NewDecoder(ioReader).Decode(&resp); err != nil {
		return err
	}

	if resp.Error != nil {
		var rpcErr rpcError
		if err := json.Unmarshal(*resp.Error, &rpcErr); err != nil {
			return err
		}

		if rpcErr.Message != "" {
			return errors.New(rpcErr.Message)
		}

		respError := rpcErr.decodeErrorCode()
		if respError != "" {
			return errors.New(respError)
		}
	}

	if resp.Result != nil && reply != nil {
		return json.Unmarshal(*resp.Result, reply)
	}

	return errors.New(emptyResponse)
}

func (client QuobyteClient) sendRequest(method string, request interface{}, response interface{}) error {
	message, err := encodeRequest(method, request)
	if err != nil {
		return err
	}
	fmt.Printf("Sending JsonRPC message: %[1]s \n", message)
	req, err := http.NewRequest("POST", client.url, bytes.NewBuffer(message))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.SetBasicAuth(client.username, client.password)
	resp, err := client.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		log.Printf("Warning: HTTP status code for request is %s\n", strconv.Itoa(resp.StatusCode))
	}
	return decodeResponse(resp.Body, &response)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"net/http"
	"time"

	"github.com/gitpods/gitpods/authorization"
	"github.com/gitpods/gitpods/cmd"
	"github.com/gitpods/gitpods/repository"
	"github.com/gitpods/gitpods/session"
	"github.com/gitpods/gitpods/user"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/prometheus"
	_ "github.com/lib/pq"
	"github.com/oklog/oklog/pkg/group"
	"github.com/pressly/chi"
	prom "github.com/prometheus/client_golang/prometheus"
	"github.com/urfave/cli"
)

type apiConf struct {
	Addr              string
	ListenAddrPrivate string
	APIPrefix         string
	DatabaseDriver    string
	DatabaseDSN       string
	LogJSON           bool
	LogLevel          string
	Secret            string
}

var (
	apiConfig = apiConf{}

	apiFlags = []cli.Flag{
		cli.StringFlag{
			Name:        cmd.FlagAddr,
			EnvVar:      cmd.EnvAddr,
			Usage:       "The address gitpods API runs on",
			Value:       ":3020",
			Destination: &apiConfig.Addr,
		},
		cli.StringFlag{
			Name:        cmd.FlagListenAddrPrivate,
			EnvVar:      cmd.EnvListenAddrPrivate,
			Usage:       "The address gitpods runs a http server only for internal access",
			Value:       ":3021",
			Destination: &apiConfig.ListenAddrPrivate,
		},
		cli.StringFlag{
			Name:        cmd.FlagAPIPrefix,
			EnvVar:      cmd.EnvAPIPrefix,
			Usage:       "The prefix the api is serving from, default: /",
			Value:       "/",
			Destination: &apiConfig.APIPrefix,
		},
		cli.StringFlag{
			Name:        cmd.FlagDatabaseDriver,
			EnvVar:      cmd.EnvDatabaseDriver,
			Usage:       "The database driver to use: memory & postgres",
			Value:       "postgres",
			Destination: &apiConfig.DatabaseDriver,
		},
		cli.StringFlag{
			Name:        cmd.FlagDatabaseDSN,
			EnvVar:      cmd.EnvDatabaseDSN,
			Usage:       "The database connection data",
			Destination: &apiConfig.DatabaseDSN,
		},
		cli.StringFlag{
			Name:        cmd.FlagLogLevel,
			EnvVar:      cmd.EnvLogLevel,
			Usage:       "The log level to filter logs with before printing",
			Value:       "info",
			Destination: &apiConfig.LogLevel,
		},
		cli.BoolFlag{
			Name:        cmd.FlagLogJSON,
			EnvVar:      cmd.EnvLogJSON,
			Usage:       "The logger will log json lines",
			Destination: &apiConfig.LogJSON,
		},
		cli.StringFlag{
			Name:        cmd.FlagSecret,
			EnvVar:      cmd.EnvSecret,
			Usage:       "This secret is going to be used to generate cookies",
			Destination: &apiConfig.Secret,
		},
	}
)

func apiAction(c *cli.Context) error {
	if apiConfig.Secret == "" {
		return errors.New("the secret for the api can't be empty")
	}

	logger := cmd.NewLogger(apiConfig.LogJSON, apiConfig.LogLevel)
	logger = log.WithPrefix(logger, "app", "api")

	apiMetrics := apiMetrics()

	//
	// Stores
	//
	var (
		repositories repository.Store
		sessions     session.Store
		users        user.Store
	)

	switch apiConfig.DatabaseDriver {
	default:
		db, err := sql.Open("postgres", apiConfig.DatabaseDSN)
		if err != nil {
			return err
		}
		defer db.Close()

		users = user.NewPostgresStore(db)
		sessions = session.NewPostgresStore(db)
		repositories = repository.NewPostgresStore(db)
	}

	//
	// Services
	//
	var ss session.Service
	ss = session.NewService(sessions)
	ss = session.NewMetricsService(ss, apiMetrics.SessionsCreated, apiMetrics.SessionsCleared)

	var as authorization.Service
	as = authorization.NewService(users.(authorization.Store), ss)
	as = authorization.NewLoggingService(log.WithPrefix(logger, "service", "authorization"), as)
	as = authorization.NewMetricsService(apiMetrics.LoginAttempts, as)

	var us user.Service
	us = user.NewService(users)
	us = user.NewLoggingService(log.WithPrefix(logger, "service", "user"), us)

	var rs repository.Service
	rs = repository.NewService(repositories)
	rs = repository.NewLoggingService(log.WithPrefix(logger, "service", "repository"), rs)

	//
	// Router
	//
	router := chi.NewRouter()
	router.Use(cmd.NewRequestLogger(logger))

	// Wrap the router inside a Router handler to make it possible to listen on / or on /api.
	// Change via APIPrefix.
	router.Route(apiConfig.APIPrefix, func(router chi.Router) {
		router.Get("/", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "hi")
		})

		router.Mount("/authorize", authorization.NewHandler(as))

		router.Group(func(router chi.Router) {
			router.Use(session.Authorized(ss))

			router.Mount("/user", user.NewUserHandler(us))
			router.Mount("/users", user.NewUsersHandler(us))
			router.Mount("/users/:username/repositories", repository.NewUsersHandler(rs))

			router.Mount("/repositories/:owner/:name", repository.NewHandler(rs))
		})
	})

	if apiConfig.APIPrefix != "/" {
		router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			http.Redirect(w, r, apiConfig.APIPrefix, http.StatusPermanentRedirect)
		})
	}

	router.NotFound(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(`{"error":"Not Found"}`))
	})

	server := &http.Server{
		Addr:    apiConfig.Addr,
		Handler: router,
	}

	privateRouter := chi.NewRouter()
	privateRouter.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, http.StatusText(http.StatusOK))
	})
	privateRouter.Mount("/metrics", prom.UninstrumentedHandler())
	privateRouter.Get("/version", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "0.0.0") // TODO: Return json
	})

	privateServer := &http.Server{
		Addr:    apiConfig.ListenAddrPrivate,
		Handler: privateRouter,
	}

	var gr group.Group
	{
		gr.Add(func() error {
			dur := time.Minute
			level.Info(logger).Log("msg", "starting session cleaner", "interval", dur)
			for {
				if _, err := ss.ClearSessions(); err != nil {
					return err
				}
				time.Sleep(dur)
			}
		}, func(err error) {
		})
	}
	{
		gr.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting gitpods api",
				"addr", apiConfig.Addr,
			)
			return server.ListenAndServe()
		}, func(err error) {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
			defer cancel()
			log.With(logger, "err", err)

			if err := server.Shutdown(ctx); err != nil {
				level.Error(logger).Log("msg", "failed to shutdown http server gracefully", "err", err)
				return
			}
			level.Info(logger).Log("msg", "http server shutdown gracefully")
		})
	}
	{
		gr.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting internal gitpods api",
				"addr", apiConfig.ListenAddrPrivate,
			)
			return privateServer.ListenAndServe()
		}, func(err error) {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
			defer cancel()

			if err := privateServer.Shutdown(ctx); err != nil {
				level.Error(logger).Log(
					"msg", "ailed to shutdown internal http server gracefully",
					"err", err,
				)
				return
			}
			level.Info(logger).Log("msg", "internal http server shutdown gracefully")
		})
	}

	return gr.Run()
}

type APIMetrics struct {
	LoginAttempts   metrics.Counter
	SessionsCreated metrics.Counter
	SessionsCleared metrics.Counter
}

func apiMetrics() *APIMetrics {
	namespace := "gitpods"

	return &APIMetrics{
		LoginAttempts: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "authentication",
			Name:      "login_attempts_total",
			Help:      "Number of login attempts that succeeded and failed",
		}, []string{"status"}),
		SessionsCreated: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "sessions",
			Name:      "created_total",
			Help:      "Number of created sessions",
		}, []string{}),
		SessionsCleared: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "sessions",
			Name:      "cleared_total",
			Help:      "Number of cleared sessions",
		}, []string{}),
	}
}
<commit_msg>Return a 200 OK on / if API prefix is not /<commit_after>package main

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"net/http"
	"time"

	"github.com/gitpods/gitpods/authorization"
	"github.com/gitpods/gitpods/cmd"
	"github.com/gitpods/gitpods/repository"
	"github.com/gitpods/gitpods/session"
	"github.com/gitpods/gitpods/user"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/prometheus"
	_ "github.com/lib/pq"
	"github.com/oklog/oklog/pkg/group"
	"github.com/pressly/chi"
	prom "github.com/prometheus/client_golang/prometheus"
	"github.com/urfave/cli"
)

type apiConf struct {
	Addr              string
	ListenAddrPrivate string
	APIPrefix         string
	DatabaseDriver    string
	DatabaseDSN       string
	LogJSON           bool
	LogLevel          string
	Secret            string
}

var (
	apiConfig = apiConf{}

	apiFlags = []cli.Flag{
		cli.StringFlag{
			Name:        cmd.FlagAddr,
			EnvVar:      cmd.EnvAddr,
			Usage:       "The address gitpods API runs on",
			Value:       ":3020",
			Destination: &apiConfig.Addr,
		},
		cli.StringFlag{
			Name:        cmd.FlagListenAddrPrivate,
			EnvVar:      cmd.EnvListenAddrPrivate,
			Usage:       "The address gitpods runs a http server only for internal access",
			Value:       ":3021",
			Destination: &apiConfig.ListenAddrPrivate,
		},
		cli.StringFlag{
			Name:        cmd.FlagAPIPrefix,
			EnvVar:      cmd.EnvAPIPrefix,
			Usage:       "The prefix the api is serving from, default: /",
			Value:       "/",
			Destination: &apiConfig.APIPrefix,
		},
		cli.StringFlag{
			Name:        cmd.FlagDatabaseDriver,
			EnvVar:      cmd.EnvDatabaseDriver,
			Usage:       "The database driver to use: memory & postgres",
			Value:       "postgres",
			Destination: &apiConfig.DatabaseDriver,
		},
		cli.StringFlag{
			Name:        cmd.FlagDatabaseDSN,
			EnvVar:      cmd.EnvDatabaseDSN,
			Usage:       "The database connection data",
			Destination: &apiConfig.DatabaseDSN,
		},
		cli.StringFlag{
			Name:        cmd.FlagLogLevel,
			EnvVar:      cmd.EnvLogLevel,
			Usage:       "The log level to filter logs with before printing",
			Value:       "info",
			Destination: &apiConfig.LogLevel,
		},
		cli.BoolFlag{
			Name:        cmd.FlagLogJSON,
			EnvVar:      cmd.EnvLogJSON,
			Usage:       "The logger will log json lines",
			Destination: &apiConfig.LogJSON,
		},
		cli.StringFlag{
			Name:        cmd.FlagSecret,
			EnvVar:      cmd.EnvSecret,
			Usage:       "This secret is going to be used to generate cookies",
			Destination: &apiConfig.Secret,
		},
	}
)

func apiAction(c *cli.Context) error {
	if apiConfig.Secret == "" {
		return errors.New("the secret for the api can't be empty")
	}

	logger := cmd.NewLogger(apiConfig.LogJSON, apiConfig.LogLevel)
	logger = log.WithPrefix(logger, "app", "api")

	apiMetrics := apiMetrics()

	//
	// Stores
	//
	var (
		repositories repository.Store
		sessions     session.Store
		users        user.Store
	)

	switch apiConfig.DatabaseDriver {
	default:
		db, err := sql.Open("postgres", apiConfig.DatabaseDSN)
		if err != nil {
			return err
		}
		defer db.Close()

		users = user.NewPostgresStore(db)
		sessions = session.NewPostgresStore(db)
		repositories = repository.NewPostgresStore(db)
	}

	//
	// Services
	//
	var ss session.Service
	ss = session.NewService(sessions)
	ss = session.NewMetricsService(ss, apiMetrics.SessionsCreated, apiMetrics.SessionsCleared)

	var as authorization.Service
	as = authorization.NewService(users.(authorization.Store), ss)
	as = authorization.NewLoggingService(log.WithPrefix(logger, "service", "authorization"), as)
	as = authorization.NewMetricsService(apiMetrics.LoginAttempts, as)

	var us user.Service
	us = user.NewService(users)
	us = user.NewLoggingService(log.WithPrefix(logger, "service", "user"), us)

	var rs repository.Service
	rs = repository.NewService(repositories)
	rs = repository.NewLoggingService(log.WithPrefix(logger, "service", "repository"), rs)

	//
	// Router
	//
	router := chi.NewRouter()
	router.Use(cmd.NewRequestLogger(logger))

	// Wrap the router inside a Router handler to make it possible to listen on / or on /api.
	// Change via APIPrefix.
	router.Route(apiConfig.APIPrefix, func(router chi.Router) {
		router.Get("/", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "hi")
		})

		router.Mount("/authorize", authorization.NewHandler(as))

		router.Group(func(router chi.Router) {
			router.Use(session.Authorized(ss))

			router.Mount("/user", user.NewUserHandler(us))
			router.Mount("/users", user.NewUsersHandler(us))
			router.Mount("/users/:username/repositories", repository.NewUsersHandler(rs))

			router.Mount("/repositories/:owner/:name", repository.NewHandler(rs))
		})
	})

	if apiConfig.APIPrefix != "/" {
		router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "API is available at ", apiConfig.APIPrefix)
		})
	}

	router.NotFound(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(`{"error":"Not Found"}`))
	})

	server := &http.Server{
		Addr:    apiConfig.Addr,
		Handler: router,
	}

	privateRouter := chi.NewRouter()
	privateRouter.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, http.StatusText(http.StatusOK))
	})
	privateRouter.Mount("/metrics", prom.UninstrumentedHandler())
	privateRouter.Get("/version", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "0.0.0") // TODO: Return json
	})

	privateServer := &http.Server{
		Addr:    apiConfig.ListenAddrPrivate,
		Handler: privateRouter,
	}

	var gr group.Group
	{
		gr.Add(func() error {
			dur := time.Minute
			level.Info(logger).Log("msg", "starting session cleaner", "interval", dur)
			for {
				if _, err := ss.ClearSessions(); err != nil {
					return err
				}
				time.Sleep(dur)
			}
		}, func(err error) {
		})
	}
	{
		gr.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting gitpods api",
				"addr", apiConfig.Addr,
			)
			return server.ListenAndServe()
		}, func(err error) {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
			defer cancel()
			log.With(logger, "err", err)

			if err := server.Shutdown(ctx); err != nil {
				level.Error(logger).Log("msg", "failed to shutdown http server gracefully", "err", err)
				return
			}
			level.Info(logger).Log("msg", "http server shutdown gracefully")
		})
	}
	{
		gr.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting internal gitpods api",
				"addr", apiConfig.ListenAddrPrivate,
			)
			return privateServer.ListenAndServe()
		}, func(err error) {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
			defer cancel()

			if err := privateServer.Shutdown(ctx); err != nil {
				level.Error(logger).Log(
					"msg", "ailed to shutdown internal http server gracefully",
					"err", err,
				)
				return
			}
			level.Info(logger).Log("msg", "internal http server shutdown gracefully")
		})
	}

	return gr.Run()
}

type APIMetrics struct {
	LoginAttempts   metrics.Counter
	SessionsCreated metrics.Counter
	SessionsCleared metrics.Counter
}

func apiMetrics() *APIMetrics {
	namespace := "gitpods"

	return &APIMetrics{
		LoginAttempts: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "authentication",
			Name:      "login_attempts_total",
			Help:      "Number of login attempts that succeeded and failed",
		}, []string{"status"}),
		SessionsCreated: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "sessions",
			Name:      "created_total",
			Help:      "Number of created sessions",
		}, []string{}),
		SessionsCleared: prometheus.NewCounterFrom(prom.CounterOpts{
			Namespace: namespace,
			Subsystem: "sessions",
			Name:      "cleared_total",
			Help:      "Number of cleared sessions",
		}, []string{}),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/constabulary/gb"
	"github.com/constabulary/gb/cmd"
	"github.com/constabulary/gb/cmd/gb/internal/match"
	"github.com/constabulary/gb/internal/debug"
)

var (
	fs  = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	cwd string
)

const (
	// disable to keep working directory
	destroyContext = true
)

func init() {
	fs.StringVar(&cwd, "R", cmd.MustGetwd(), "set the project root") // actually the working directory to start the project root search
	fs.Usage = usage
}

var commands = make(map[string]*cmd.Command)

// registerCommand registers a command for main.
// registerCommand should only be called from init().
func registerCommand(command *cmd.Command) {
	commands[command.Name] = command
}

// atExit functions are called in sequence at the exit of the program.
var atExit []func() error

// exit runs all atExit functions, then calls os.Exit(code).
func exit(code int) {
	for _, fn := range atExit {
		fn()
	}
	os.Exit(code)
}

func fatalf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "FATAL: "+format+"\n", args...)
	exit(1)
}

func main() {
	args := os.Args
	if len(args) < 2 || args[1] == "-h" {
		fs.Usage() // usage calles exit(2)
	}
	name := args[1]
	if name == "help" {
		help(args[2:])
		exit(0)
	}

	command := lookupCommand(name)

	// add extra flags if necessary
	if command.AddFlags != nil {
		command.AddFlags(fs)
	}

	var err error
	if command.FlagParse != nil {
		err = command.FlagParse(fs, args)
	} else {
		err = fs.Parse(args[2:])
	}
	if err != nil {
		fatalf("could not parse flags: %v", err)
	}

	args = fs.Args() // reset args to the leftovers from fs.Parse

	debug.Debugf("args: %v", args)

	if command == commands["plugin"] {
		args = append([]string{name}, args...)
	}
	cwd, err := filepath.Abs(cwd) // if cwd was passed in via -R, make sure it is absolute
	if err != nil {
		fatalf("could not make project root absolute: %v", err)
	}

	ctx, err := newContext(cwd)
	if err != nil {
		fatalf("unable to construct context: %v", err)
	}

	if !command.SkipParseArgs {
		srcdir := filepath.Join(ctx.Projectdir(), "src")
		args = match.ImportPaths(srcdir, cwd, args)
	}

	debug.Debugf("args: %v", args)

	if destroyContext {
		atExit = append(atExit, ctx.Destroy)
	}

	if err := command.Run(ctx, args); err != nil {
		fatalf("command %q failed: %v", name, err)
	}
	exit(0)
}

func lookupCommand(name string) *cmd.Command {
	command, ok := commands[name]
	if (command != nil && !command.Runnable()) || !ok {
		plugin, err := lookupPlugin(name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "FATAL: unknown command %q\n", name)
			fs.Usage() // usage calles exit(2)
		}
		command = &cmd.Command{
			Run: func(ctx *gb.Context, args []string) error {
				args = append([]string{plugin}, args...)

				env := cmd.MergeEnv(os.Environ(), map[string]string{
					"GB_PROJECT_DIR": ctx.Projectdir(),
				})

				cmd := exec.Cmd{
					Path: plugin,
					Args: args,
					Env:  env,

					Stdin:  os.Stdin,
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				}

				return cmd.Run()
			},
			// plugin should not interpret arguments
			SkipParseArgs: true,
		}
	}
	return command
}

func newContext(cwd string) (*gb.Context, error) {
	return cmd.NewContext(
		cwd, // project root
		gb.GcToolchain(),
		gb.Gcflags(gcflags...),
		gb.Ldflags(ldflags...),
		gb.Tags(buildtags...),
		func(c *gb.Context) error {
			if !race {
				return nil
			}

			// check this is a supported platform
			if runtime.GOARCH != "amd64" {
				fatalf("race detector not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
			}
			switch runtime.GOOS {
			case "linux", "windows", "darwin", "freebsd":
				// supported
			default:
				fatalf("race detector not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
			}

			// check the race runtime is built
			_, err := os.Stat(filepath.Join(runtime.GOROOT(), "pkg", fmt.Sprintf("%s_%s_race", runtime.GOOS, runtime.GOARCH), "runtime.a"))
			if os.IsNotExist(err) || err != nil {
				fatalf("go installation at %s is missing race support. See https://getgb.io/faq/#missing-race-support", runtime.GOROOT())
			}

			return gb.WithRace(c)
		},
	)
}
<commit_msg>cmd/gb: move some conditional logic out of main.main (#613)<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/constabulary/gb"
	"github.com/constabulary/gb/cmd"
	"github.com/constabulary/gb/cmd/gb/internal/match"
	"github.com/constabulary/gb/internal/debug"
)

var (
	fs  = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	cwd string
)

const (
	// disable to keep working directory
	destroyContext = true
)

func init() {
	fs.StringVar(&cwd, "R", cmd.MustGetwd(), "set the project root") // actually the working directory to start the project root search
	fs.Usage = usage
}

var commands = make(map[string]*cmd.Command)

// registerCommand registers a command for main.
// registerCommand should only be called from init().
func registerCommand(command *cmd.Command) {

	// add a dummy default AddFlags field if none provided.
	if command.AddFlags == nil {
		command.AddFlags = func(*flag.FlagSet) {}
	}

	// add the default flag parsing if not overrriden.
	if command.FlagParse == nil {
		command.FlagParse = func(fs *flag.FlagSet, args []string) error {
			return fs.Parse(args[2:])
		}
	}

	commands[command.Name] = command
}

// atExit functions are called in sequence at the exit of the program.
var atExit []func() error

// exit runs all atExit functions, then calls os.Exit(code).
func exit(code int) {
	for _, fn := range atExit {
		fn()
	}
	os.Exit(code)
}

func fatalf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "FATAL: "+format+"\n", args...)
	exit(1)
}

func main() {
	args := os.Args
	if len(args) < 2 || args[1] == "-h" {
		fs.Usage() // usage calles exit(2)
	}
	name := args[1]
	if name == "help" {
		help(args[2:])
		exit(0)
	}

	command := lookupCommand(name)

	// add extra flags if necessary
	command.AddFlags(fs)

	// parse 'em
	err := command.FlagParse(fs, args)
	if err != nil {
		fatalf("could not parse flags: %v", err)
	}

	// reset args to the leftovers from fs.Parse
	args = fs.Args()

	// if this is the plugin command, ensure the name of the
	// plugin is first in the list of arguments.
	if command == commands["plugin"] {
		args = append([]string{name}, args...)
	}

	// if cwd was passed in via -R, make sure it is absolute
	cwd, err := filepath.Abs(cwd)
	if err != nil {
		fatalf("could not make project root absolute: %v", err)
	}

	// construct a project context at the current working directory.
	ctx, err := newContext(cwd)
	if err != nil {
		fatalf("unable to construct context: %v", err)
	}

	// unless the command wants to handle its own arguments, process
	// arguments into import paths.
	if !command.SkipParseArgs {
		srcdir := filepath.Join(ctx.Projectdir(), "src")
		args = match.ImportPaths(srcdir, cwd, args)
	}

	debug.Debugf("args: %v", args)

	if destroyContext {
		atExit = append(atExit, ctx.Destroy)
	}

	if err := command.Run(ctx, args); err != nil {
		fatalf("command %q failed: %v", name, err)
	}
	exit(0)
}

func lookupCommand(name string) *cmd.Command {
	command, ok := commands[name]
	if (command != nil && !command.Runnable()) || !ok {
		plugin, err := lookupPlugin(name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "FATAL: unknown command %q\n", name)
			fs.Usage() // usage calles exit(2)
		}
		command = &cmd.Command{
			Run: func(ctx *gb.Context, args []string) error {
				args = append([]string{plugin}, args...)

				env := cmd.MergeEnv(os.Environ(), map[string]string{
					"GB_PROJECT_DIR": ctx.Projectdir(),
				})

				cmd := exec.Cmd{
					Path: plugin,
					Args: args,
					Env:  env,

					Stdin:  os.Stdin,
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				}

				return cmd.Run()
			},
			// plugin should not interpret arguments
			SkipParseArgs: true,
			AddFlags:      func(*flag.FlagSet) {},
			FlagParse:     func(fs *flag.FlagSet, args []string) error { return fs.Parse(args[2:]) },
		}
	}
	return command
}

func newContext(cwd string) (*gb.Context, error) {
	return cmd.NewContext(
		cwd, // project root
		gb.GcToolchain(),
		gb.Gcflags(gcflags...),
		gb.Ldflags(ldflags...),
		gb.Tags(buildtags...),
		func(c *gb.Context) error {
			if !race {
				return nil
			}

			// check this is a supported platform
			if runtime.GOARCH != "amd64" {
				fatalf("race detector not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
			}
			switch runtime.GOOS {
			case "linux", "windows", "darwin", "freebsd":
				// supported
			default:
				fatalf("race detector not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
			}

			// check the race runtime is built
			_, err := os.Stat(filepath.Join(runtime.GOROOT(), "pkg", fmt.Sprintf("%s_%s_race", runtime.GOOS, runtime.GOARCH), "runtime.a"))
			if os.IsNotExist(err) || err != nil {
				fatalf("go installation at %s is missing race support. See https://getgb.io/faq/#missing-race-support", runtime.GOROOT())
			}

			return gb.WithRace(c)
		},
	)
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package cmd

import (
	"io"
	"os"

	"launchpad.net/gnuflag"
	"launchpad.net/loggo"
)

// Log supplies the necessary functionality for Commands that wish to set up
// logging.
type Log struct {
	Path    string
	Verbose bool
	Debug   bool
	Config  string
}

// AddFlags adds appropriate flags to f.
func (l *Log) AddFlags(f *gnuflag.FlagSet) {
	f.StringVar(&l.Path, "log-file", "", "path to write log to")
	// TODO(thumper): rename verbose to --show-log
	f.BoolVar(&l.Verbose, "v", false, "if set, log additional messages")
	f.BoolVar(&l.Verbose, "verbose", false, "if set, log additional messages")
	f.BoolVar(&l.Debug, "debug", false, "if set, log debugging messages")
	f.StringVar(&l.Config, "log-config", "", "specify log levels for modules")
}

// Start starts logging using the given Context.
func (l *Log) Start(ctx *Context) (err error) {
	var target io.Writer
	if l.Path != "" {
		path := ctx.AbsPath(l.Path)
		target, err = os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
		if err != nil {
			return err
		}
	} else if l.Verbose || l.Debug {
		target = ctx.Stderr
	}

	if target != nil {
		writer := loggo.NewSimpleWriter(target, &loggo.DefaultFormatter{})
		_, err = loggo.ReplaceDefaultWriter(writer)
		if err != nil {
			return err
		}
	} else {
		loggo.RemoveWriter("default")
	}
	if l.Debug {
		logger := loggo.GetLogger("juju")
		logger.SetLogLevel(loggo.DEBUG)
	}
	loggo.ConfigureLogging(l.Config)
	return nil
}
<commit_msg>Actually set INFO if --verbose.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package cmd

import (
	"io"
	"os"

	"launchpad.net/gnuflag"
	"launchpad.net/loggo"
)

// Log supplies the necessary functionality for Commands that wish to set up
// logging.
type Log struct {
	Path    string
	Verbose bool
	Debug   bool
	Config  string
}

// AddFlags adds appropriate flags to f.
func (l *Log) AddFlags(f *gnuflag.FlagSet) {
	f.StringVar(&l.Path, "log-file", "", "path to write log to")
	// TODO(thumper): rename verbose to --show-log
	f.BoolVar(&l.Verbose, "v", false, "if set, log additional messages")
	f.BoolVar(&l.Verbose, "verbose", false, "if set, log additional messages")
	f.BoolVar(&l.Debug, "debug", false, "if set, log debugging messages")
	f.StringVar(&l.Config, "log-config", "", "specify log levels for modules")
}

// Start starts logging using the given Context.
func (l *Log) Start(ctx *Context) (err error) {
	var target io.Writer
	if l.Path != "" {
		path := ctx.AbsPath(l.Path)
		target, err = os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
		if err != nil {
			return err
		}
	} else if l.Verbose || l.Debug {
		target = ctx.Stderr
	}

	if target != nil {
		writer := loggo.NewSimpleWriter(target, &loggo.DefaultFormatter{})
		_, err = loggo.ReplaceDefaultWriter(writer)
		if err != nil {
			return err
		}
	} else {
		loggo.RemoveWriter("default")
	}
	if l.Verbose || l.Debug {
		var level = loggo.INFO
		if l.Debug {
			level = loggo.DEBUG
		}
		logger := loggo.GetLogger("juju")
		logger.SetLogLevel(level)
	}
	loggo.ConfigureLogging(l.Config)
	return nil
}
<|endoftext|>