<commit_before>/*
Copyright 2017 The Kubernetes 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 auth

import (
	"crypto/rsa"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"golang.org/x/crypto/pkcs12"
	"k8s.io/klog"
)

var (
	// ErrorNoAuth indicates that no credentials are provided.
	ErrorNoAuth = fmt.Errorf("no credentials provided for Azure cloud provider")
	// Tenenatid value for Azure Stack ADFS case.
	ADFSIdentitySystem = "ADFS"
)

// AzureAuthConfig holds auth related part of cloud config
type AzureAuthConfig struct {
	// The cloud environment identifier. Takes values from https://github.com/Azure/go-autorest/blob/ec5f4903f77ed9927ac95b19ab8e44ada64c1356/autorest/azure/environments.go#L13
	Cloud string `json:"cloud,omitempty" yaml:"cloud,omitempty"`
	// The AAD Tenant ID for the Subscription that the cluster is deployed in
	TenantID string `json:"tenantId,omitempty" yaml:"tenantId,omitempty"`
	// The ClientID for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientID string `json:"aadClientId,omitempty" yaml:"aadClientId,omitempty"`
	// The ClientSecret for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientSecret string `json:"aadClientSecret,omitempty" yaml:"aadClientSecret,omitempty"`
	// The path of a client certificate for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientCertPath string `json:"aadClientCertPath,omitempty" yaml:"aadClientCertPath,omitempty"`
	// The password of the client certificate for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientCertPassword string `json:"aadClientCertPassword,omitempty" yaml:"aadClientCertPassword,omitempty"`
	// Use managed service identity for the virtual machine to access Azure ARM APIs
	UseManagedIdentityExtension bool `json:"useManagedIdentityExtension,omitempty" yaml:"useManagedIdentityExtension,omitempty"`
	// UserAssignedIdentityID contains the Client ID of the user assigned MSI which is assigned to the underlying VMs. If empty the user assigned identity is not used.
	// More details of the user assigned identity can be found at: https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview
	// For the user assigned identity specified here to be used, the UseManagedIdentityExtension has to be set to true.
	UserAssignedIdentityID string `json:"userAssignedIdentityID,omitempty" yaml:"userAssignedIdentityID,omitempty"`
	// The ID of the Azure Subscription that the cluster is deployed in
	SubscriptionID string `json:"subscriptionId,omitempty" yaml:"subscriptionId,omitempty"`
	// Identity system value for the deployment. This gets populate for Azure Stack case.
	IdentitySystem string `json:"identitySystem,omitempty" yaml:"identitySystem,omitempty"`
}

// GetServicePrincipalToken creates a new service principal token based on the configuration
func GetServicePrincipalToken(config *AzureAuthConfig, env *azure.Environment) (*adal.ServicePrincipalToken, error) {
	var tenantId string
	if strings.EqualFold(config.IdentitySystem, ADFSIdentitySystem) {
		tenantId = "adfs"
	} else {
		tenantId = config.TenantID
	}

	if config.UseManagedIdentityExtension {
		klog.V(2).Infoln("azure: using managed identity extension to retrieve access token")
		msiEndpoint, err := adal.GetMSIVMEndpoint()
		if err != nil {
			return nil, fmt.Errorf("Getting the managed service identity endpoint: %v", err)
		}
		if len(config.UserAssignedIdentityID) > 0 {
			klog.V(4).Info("azure: using User Assigned MSI ID to retrieve access token")
			return adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint,
				env.ServiceManagementEndpoint,
				config.UserAssignedIdentityID)
		}
		klog.V(4).Info("azure: using System Assigned MSI to retrieve access token")
		return adal.NewServicePrincipalTokenFromMSI(
			msiEndpoint,
			env.ServiceManagementEndpoint)
	}

	oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantId)
	if err != nil {
		return nil, fmt.Errorf("creating the OAuth config: %v", err)
	}

	if len(config.AADClientSecret) > 0 {
		klog.V(2).Infoln("azure: using client_id+client_secret to retrieve access token")
		return adal.NewServicePrincipalToken(
			*oauthConfig,
			config.AADClientID,
			config.AADClientSecret,
			env.ServiceManagementEndpoint)
	}

	if len(config.AADClientCertPath) > 0 && len(config.AADClientCertPassword) > 0 {
		klog.V(2).Infoln("azure: using jwt client_assertion (client_cert+client_private_key) to retrieve access token")
		certData, err := ioutil.ReadFile(config.AADClientCertPath)
		if err != nil {
			return nil, fmt.Errorf("reading the client certificate from file %s: %v", config.AADClientCertPath, err)
		}
		certificate, privateKey, err := decodePkcs12(certData, config.AADClientCertPassword)
		if err != nil {
			return nil, fmt.Errorf("decoding the client certificate: %v", err)
		}
		return adal.NewServicePrincipalTokenFromCertificate(
			*oauthConfig,
			config.AADClientID,
			certificate,
			privateKey,
			env.ServiceManagementEndpoint)
	}

	return nil, ErrorNoAuth
}

// ParseAzureEnvironment returns azure environment by name
func ParseAzureEnvironment(cloudName string) (*azure.Environment, error) {
	var env azure.Environment
	var err error
	if cloudName == "" {
		env = azure.PublicCloud
	} else {
		env, err = azure.EnvironmentFromName(cloudName)
	}
	return &env, err
}

// decodePkcs12 decodes a PKCS#12 client certificate by extracting the public certificate and
// the private RSA key
func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
	privateKey, certificate, err := pkcs12.Decode(pkcs, password)
	if err != nil {
		return nil, nil, fmt.Errorf("decoding the PKCS#12 client certificate: %v", err)
	}
	rsaPrivateKey, isRsaKey := privateKey.(*rsa.PrivateKey)
	if !isRsaKey {
		return nil, nil, fmt.Errorf("PKCS#12 certificate must contain a RSA private key")
	}

	return certificate, rsaPrivateKey, nil
}
<commit_msg>fixed golint issues.<commit_after>/*
Copyright 2017 The Kubernetes 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 auth

import (
	"crypto/rsa"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"golang.org/x/crypto/pkcs12"
	"k8s.io/klog"
)

var (
	// ErrorNoAuth indicates that no credentials are provided.
	ErrorNoAuth = fmt.Errorf("no credentials provided for Azure cloud provider")
	// ADFSIdentitySystem indicates value of tenantId for ADFS on Azure Stack.
	ADFSIdentitySystem = "ADFS"
)

// AzureAuthConfig holds auth related part of cloud config
type AzureAuthConfig struct {
	// The cloud environment identifier. Takes values from https://github.com/Azure/go-autorest/blob/ec5f4903f77ed9927ac95b19ab8e44ada64c1356/autorest/azure/environments.go#L13
	Cloud string `json:"cloud,omitempty" yaml:"cloud,omitempty"`
	// The AAD Tenant ID for the Subscription that the cluster is deployed in
	TenantID string `json:"tenantId,omitempty" yaml:"tenantId,omitempty"`
	// The ClientID for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientID string `json:"aadClientId,omitempty" yaml:"aadClientId,omitempty"`
	// The ClientSecret for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientSecret string `json:"aadClientSecret,omitempty" yaml:"aadClientSecret,omitempty"`
	// The path of a client certificate for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientCertPath string `json:"aadClientCertPath,omitempty" yaml:"aadClientCertPath,omitempty"`
	// The password of the client certificate for an AAD application with RBAC access to talk to Azure RM APIs
	AADClientCertPassword string `json:"aadClientCertPassword,omitempty" yaml:"aadClientCertPassword,omitempty"`
	// Use managed service identity for the virtual machine to access Azure ARM APIs
	UseManagedIdentityExtension bool `json:"useManagedIdentityExtension,omitempty" yaml:"useManagedIdentityExtension,omitempty"`
	// UserAssignedIdentityID contains the Client ID of the user assigned MSI which is assigned to the underlying VMs. If empty the user assigned identity is not used.
	// More details of the user assigned identity can be found at: https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview
	// For the user assigned identity specified here to be used, the UseManagedIdentityExtension has to be set to true.
	UserAssignedIdentityID string `json:"userAssignedIdentityID,omitempty" yaml:"userAssignedIdentityID,omitempty"`
	// The ID of the Azure Subscription that the cluster is deployed in
	SubscriptionID string `json:"subscriptionId,omitempty" yaml:"subscriptionId,omitempty"`
	// Identity system value for the deployment. This gets populate for Azure Stack case.
	IdentitySystem string `json:"identitySystem,omitempty" yaml:"identitySystem,omitempty"`
}

// GetServicePrincipalToken creates a new service principal token based on the configuration
func GetServicePrincipalToken(config *AzureAuthConfig, env *azure.Environment) (*adal.ServicePrincipalToken, error) {
	var tenantID string
	if strings.EqualFold(config.IdentitySystem, ADFSIdentitySystem) {
		tenantID = "adfs"
	} else {
		tenantID = config.TenantID
	}

	if config.UseManagedIdentityExtension {
		klog.V(2).Infoln("azure: using managed identity extension to retrieve access token")
		msiEndpoint, err := adal.GetMSIVMEndpoint()
		if err != nil {
			return nil, fmt.Errorf("Getting the managed service identity endpoint: %v", err)
		}
		if len(config.UserAssignedIdentityID) > 0 {
			klog.V(4).Info("azure: using User Assigned MSI ID to retrieve access token")
			return adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint,
				env.ServiceManagementEndpoint,
				config.UserAssignedIdentityID)
		}
		klog.V(4).Info("azure: using System Assigned MSI to retrieve access token")
		return adal.NewServicePrincipalTokenFromMSI(
			msiEndpoint,
			env.ServiceManagementEndpoint)
	}

	oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
	if err != nil {
		return nil, fmt.Errorf("creating the OAuth config: %v", err)
	}

	if len(config.AADClientSecret) > 0 {
		klog.V(2).Infoln("azure: using client_id+client_secret to retrieve access token")
		return adal.NewServicePrincipalToken(
			*oauthConfig,
			config.AADClientID,
			config.AADClientSecret,
			env.ServiceManagementEndpoint)
	}

	if len(config.AADClientCertPath) > 0 && len(config.AADClientCertPassword) > 0 {
		klog.V(2).Infoln("azure: using jwt client_assertion (client_cert+client_private_key) to retrieve access token")
		certData, err := ioutil.ReadFile(config.AADClientCertPath)
		if err != nil {
			return nil, fmt.Errorf("reading the client certificate from file %s: %v", config.AADClientCertPath, err)
		}
		certificate, privateKey, err := decodePkcs12(certData, config.AADClientCertPassword)
		if err != nil {
			return nil, fmt.Errorf("decoding the client certificate: %v", err)
		}
		return adal.NewServicePrincipalTokenFromCertificate(
			*oauthConfig,
			config.AADClientID,
			certificate,
			privateKey,
			env.ServiceManagementEndpoint)
	}

	return nil, ErrorNoAuth
}

// ParseAzureEnvironment returns azure environment by name
func ParseAzureEnvironment(cloudName string) (*azure.Environment, error) {
	var env azure.Environment
	var err error
	if cloudName == "" {
		env = azure.PublicCloud
	} else {
		env, err = azure.EnvironmentFromName(cloudName)
	}
	return &env, err
}

// decodePkcs12 decodes a PKCS#12 client certificate by extracting the public certificate and
// the private RSA key
func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
	privateKey, certificate, err := pkcs12.Decode(pkcs, password)
	if err != nil {
		return nil, nil, fmt.Errorf("decoding the PKCS#12 client certificate: %v", err)
	}
	rsaPrivateKey, isRsaKey := privateKey.(*rsa.PrivateKey)
	if !isRsaKey {
		return nil, nil, fmt.Errorf("PKCS#12 certificate must contain a RSA private key")
	}

	return certificate, rsaPrivateKey, nil
}
<|endoftext|>


<commit_before>package edward_test

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"testing"

	"github.com/pkg/errors"
	"github.com/theothertomelliott/gopsutil-nocgo/process"
	"github.com/yext/edward/tracker"
)

// Path to the Edward executable as built
var edwardExecutable string

func TestMain(m *testing.M) {
	buildDir, err := ioutil.TempDir("", "edwardTest")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(buildDir)

	edwardExecutable = path.Join(buildDir, "edward")

	cmd := exec.Command("go", "build", "-o", edwardExecutable, "github.com/yext/edward")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	os.Exit(m.Run())
}

type testFollower struct {
	states   map[string]string
	messages []string
}

func newTestFollower() *testFollower {
	return &testFollower{
		states: make(map[string]string),
	}
}

func (f *testFollower) Handle(update tracker.Task) {
	var names []string
	for _, task := range update.Lineage() {
		if task.Name() != "" {
			names = append(names, task.Name())
		}
	}

	fullName := strings.Join(names, " > ")
	f.states[fullName] = update.State().String()
	f.messages = append(f.messages, update.Messages()...)
}
func (f *testFollower) Done() {}

// getRunnerAndServiceProcesses returns all processes and children spawned by this test
func getRunnerAndServiceProcesses(t *testing.T) []*process.Process {
	var processes []*process.Process
	testProcess, err := process.NewProcess(int32(os.Getpid()))
	if err != nil {
		t.Fatal(err)
	}
	runners, err := testProcess.Children()
	if err != nil {
		t.Fatalf("No processes found")
	}
	processes = append(processes, runners...)
	for _, runner := range runners {
		services, err := runner.Children()
		if err != nil {
			t.Fatalf("No processes found")
		}
		processes = append(processes, services...)
	}
	return processes
}

// verifyAndStopRunners expects that there will be the specified number of runners in progress,
// and that the runners are behaving as expected (exactly one child service, etc).
// Once verified, it will kill the runners and their child services.
func verifyAndStopRunners(t *testing.T, serviceCount int) {
	testProcess, err := process.NewProcess(int32(os.Getpid()))
	if err != nil {
		t.Fatal(err)
	}
	children, err := testProcess.Children()
	if err != nil {
		if serviceCount != 0 {
			t.Fatalf("No processes found, expected %d", serviceCount)
		}
	}
	if len(children) != serviceCount {
		// We can't know which test or operation this would be for, so don't try to stop anything
		t.Fatalf("Expected %d children, got %d", serviceCount, len(children))
	}
	for _, child := range children {
		err = verifyAndStopRunner(t, child)
		if err != nil {
			t.Fatal(err)
		}
	}
}

// verifyAndStopRunner will check that a runner process has exactly one child service,
// and then kill the service, expecting the runner to die.
func verifyAndStopRunner(t *testing.T, runner *process.Process) error {
	defer func() {
		if running, _ := runner.IsRunning(); running {
			return
		}
		t.Error("Expected stopping children to kill runner process")
		err := runner.Kill()
		if err != nil {
			t.Fatal("Could not kill runner:", err)
		}
	}()

	cmdline, err := runner.CmdlineSlice()
	if err != nil {
		return errors.WithStack(err)
	}
	if cmdline[0] == "edward" || cmdline[1] == "run" {
		services, err := runner.Children()
		if err != nil {
			return errors.WithStack(err)
		}
		if len(services) != 1 {
			t.Errorf("Expected 1 child, got %v", len(services))
		}
		for _, service := range services {
			err = service.Kill()
			if err != nil {
				return errors.WithStack(err)
			}
		}
	} else {
		t.Errorf("Expected an edward run command, got: %v", cmdline)
	}
	return nil
}
<commit_msg>Output a list of child names when we see an unexpected number of children.<commit_after>package edward_test

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"testing"

	"github.com/pkg/errors"
	"github.com/theothertomelliott/gopsutil-nocgo/process"
	"github.com/yext/edward/tracker"
)

// Path to the Edward executable as built
var edwardExecutable string

func TestMain(m *testing.M) {
	buildDir, err := ioutil.TempDir("", "edwardTest")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(buildDir)

	edwardExecutable = path.Join(buildDir, "edward")

	cmd := exec.Command("go", "build", "-o", edwardExecutable, "github.com/yext/edward")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	os.Exit(m.Run())
}

type testFollower struct {
	states   map[string]string
	messages []string
}

func newTestFollower() *testFollower {
	return &testFollower{
		states: make(map[string]string),
	}
}

func (f *testFollower) Handle(update tracker.Task) {
	var names []string
	for _, task := range update.Lineage() {
		if task.Name() != "" {
			names = append(names, task.Name())
		}
	}

	fullName := strings.Join(names, " > ")
	f.states[fullName] = update.State().String()
	f.messages = append(f.messages, update.Messages()...)
}
func (f *testFollower) Done() {}

// getRunnerAndServiceProcesses returns all processes and children spawned by this test
func getRunnerAndServiceProcesses(t *testing.T) []*process.Process {
	var processes []*process.Process
	testProcess, err := process.NewProcess(int32(os.Getpid()))
	if err != nil {
		t.Fatal(err)
	}
	runners, err := testProcess.Children()
	if err != nil {
		t.Fatalf("No processes found")
	}
	processes = append(processes, runners...)
	for _, runner := range runners {
		services, err := runner.Children()
		if err != nil {
			t.Fatalf("No processes found")
		}
		processes = append(processes, services...)
	}
	return processes
}

// verifyAndStopRunners expects that there will be the specified number of runners in progress,
// and that the runners are behaving as expected (exactly one child service, etc).
// Once verified, it will kill the runners and their child services.
func verifyAndStopRunners(t *testing.T, serviceCount int) {
	testProcess, err := process.NewProcess(int32(os.Getpid()))
	if err != nil {
		t.Fatal(err)
	}
	children, err := testProcess.Children()
	if err != nil {
		if serviceCount != 0 {
			t.Fatalf("No processes found, expected %d", serviceCount)
		}
	}
	if len(children) != serviceCount {
		// We can't know which test or operation this would be for, so don't try to stop anything
		var childNames []string
		for _, child := range children {
			cmdline, err := child.Cmdline()
			if err != nil {
				t.Errorf("Error getting cmdline: %v", err)
			}
			childNames = append(childNames, cmdline)
		}
		t.Fatalf("Expected %d children, got %s", serviceCount, strings.Join(childNames, ", "))
	}
	for _, child := range children {
		err = verifyAndStopRunner(t, child)
		if err != nil {
			t.Fatal(err)
		}
	}
}

// verifyAndStopRunner will check that a runner process has exactly one child service,
// and then kill the service, expecting the runner to die.
func verifyAndStopRunner(t *testing.T, runner *process.Process) error {
	defer func() {
		if running, _ := runner.IsRunning(); running {
			return
		}
		t.Error("Expected stopping children to kill runner process")
		err := runner.Kill()
		if err != nil {
			t.Fatal("Could not kill runner:", err)
		}
	}()

	cmdline, err := runner.CmdlineSlice()
	if err != nil {
		return errors.WithStack(err)
	}
	if cmdline[0] == "edward" || cmdline[1] == "run" {
		services, err := runner.Children()
		if err != nil {
			return errors.WithStack(err)
		}
		if len(services) != 1 {
			t.Errorf("Expected 1 child, got %v", len(services))
		}
		for _, service := range services {
			err = service.Kill()
			if err != nil {
				return errors.WithStack(err)
			}
		}
	} else {
		t.Errorf("Expected an edward run command, got: %v", cmdline)
	}
	return nil
}
<|endoftext|>


<commit_before>package mpmulticore

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphDef = map[string]mp.Graphs{
	"multicore.cpu.#": {
		Label: "MultiCore CPU",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "guest_nice", Label: "guest_nice", Diff: false, Stacked: true},
			{Name: "guest", Label: "guest", Diff: false, Stacked: true},
			{Name: "steal", Label: "steal", Diff: false, Stacked: true},
			{Name: "softirq", Label: "softirq", Diff: false, Stacked: true},
			{Name: "irq", Label: "irq", Diff: false, Stacked: true},
			{Name: "iowait", Label: "ioWait", Diff: false, Stacked: true},
			{Name: "idle", Label: "idle", Diff: false, Stacked: true},
			{Name: "system", Label: "system", Diff: false, Stacked: true},
			{Name: "nice", Label: "nice", Diff: false, Stacked: true},
			{Name: "user", Label: "user", Diff: false, Stacked: true},
		},
	},
	"multicore.loadavg_per_core": {
		Label: "MultiCore loadavg5 per core",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "loadavg5", Label: "loadavg5", Diff: false, Stacked: false},
		},
	},
}

type saveItem struct {
	LastTime       time.Time
	ProcStatsByCPU map[string]procStats
}

type procStats struct {
	User      *uint64 `json:"user"`
	Nice      *uint64 `json:"nice"`
	System    *uint64 `json:"system"`
	Idle      *uint64 `json:"idle"`
	IoWait    *uint64 `json:"iowait"`
	Irq       *uint64 `json:"irq"`
	SoftIrq   *uint64 `json:"softirq"`
	Steal     *uint64 `json:"steal"`
	Guest     *uint64 `json:"guest"`
	GuestNice *uint64 `json:"guest_nice"`
	Total     uint64  `json:"total"`
}

type cpuPercentages struct {
	CPUName   string
	User      *float64
	Nice      *float64
	System    *float64
	Idle      *float64
	IoWait    *float64
	Irq       *float64
	SoftIrq   *float64
	Steal     *float64
	Guest     *float64
	GuestNice *float64
}

func parseProcStat(out io.Reader) (map[string]procStats, error) {
	scanner := bufio.NewScanner(out)
	var result = make(map[string]procStats)
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		key := fields[0]
		values := fields[1:]

		// skip total cpu usage
		if key == "cpu" {
			continue
		}

		var stats procStats
		statPtrs := []**uint64{
			&stats.User,
			&stats.Nice,
			&stats.System,
			&stats.Idle,
			&stats.IoWait,
			&stats.Irq,
			&stats.SoftIrq,
			&stats.Steal,
			&stats.Guest,
			&stats.GuestNice,
		}

		for i, valStr := range values {
			val, err := strconv.ParseUint(valStr, 10, 64)
			if err != nil {
				return nil, err
			}
			*statPtrs[i] = &val
			stats.Total += val
		}

		// Since cpustat[CPUTIME_USER] includes cpustat[CPUTIME_GUEST], subtract the duplicated values from total.
		// https://github.com/torvalds/linux/blob/4ec9f7a18/kernel/sched/cputime.c#L151-L158
		if stats.Guest != nil {
			stats.Total -= *stats.Guest
			*stats.User -= *stats.Guest
		}

		// cpustat[CPUTIME_NICE] includes cpustat[CPUTIME_GUEST_NICE]
		if stats.GuestNice != nil {
			stats.Total -= *stats.GuestNice
			*stats.Nice -= *stats.GuestNice
		}

		result[key] = stats
	}
	return result, nil
}

func collectProcStatValues() (map[string]procStats, error) {
	file, err := os.Open("/proc/stat")
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return parseProcStat(file)
}

func saveValues(tempFileName string, values map[string]procStats, now time.Time) error {
	f, err := os.Create(tempFileName)
	if err != nil {
		return err
	}
	defer f.Close()

	s := saveItem{
		LastTime:       now,
		ProcStatsByCPU: values,
	}

	encoder := json.NewEncoder(f)
	err = encoder.Encode(s)
	if err != nil {
		return err
	}

	return nil
}

func fetchSavedItem(tempFileName string) (*saveItem, error) {
	f, err := os.Open(tempFileName)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	defer f.Close()

	var stat saveItem
	decoder := json.NewDecoder(f)
	err = decoder.Decode(&stat)
	if err != nil {
		return nil, err
	}
	return &stat, nil
}

func calcCPUUsage(currentValues map[string]procStats, now time.Time, savedItem *saveItem) ([]cpuPercentages, error) {
	if now.Sub(savedItem.LastTime).Seconds() > 600 {
		return nil, errors.New("Too long duration")
	}

	var result []cpuPercentages
	for name, current := range currentValues {
		last, ok := savedItem.ProcStatsByCPU[name]
		if !ok {
			continue
		}
		if last.Total > current.Total {
			return nil, errors.New("cpu counter has been reset")
		}

		user := calculatePercentage(current.User, last.User, current.Total, last.Total)
		nice := calculatePercentage(current.Nice, last.Nice, current.Total, last.Total)
		system := calculatePercentage(current.System, last.System, current.Total, last.Total)
		idle := calculatePercentage(current.Idle, last.Idle, current.Total, last.Total)
		iowait := calculatePercentage(current.IoWait, last.IoWait, current.Total, last.Total)
		irq := calculatePercentage(current.Irq, last.Irq, current.Total, last.Total)
		softirq := calculatePercentage(current.SoftIrq, last.SoftIrq, current.Total, last.Total)
		steal := calculatePercentage(current.Steal, last.Steal, current.Total, last.Total)
		guest := calculatePercentage(current.Guest, last.Guest, current.Total, last.Total)
		// guest_nice available since Linux 2.6.33 (ref: man proc)
		guestNice := calculatePercentage(current.GuestNice, last.GuestNice, current.Total, last.Total)

		result = append(result, cpuPercentages{
			CPUName:   name,
			User:      user,
			Nice:      nice,
			System:    system,
			Idle:      idle,
			IoWait:    iowait,
			Irq:       irq,
			SoftIrq:   softirq,
			Steal:     steal,
			Guest:     guest,
			GuestNice: guestNice,
		})
	}

	return result, nil
}

func calculatePercentage(currentValue *uint64, lastValue *uint64, currentTotal uint64, lastTotal uint64) *float64 {
	if currentValue == nil || lastValue == nil {
		return nil
	}
	ret := float64(*currentValue-*lastValue) / float64(currentTotal-lastTotal) * 100.0
	return &ret
}

func fetchLoadavg5() (float64, error) {
	contentbytes, err := ioutil.ReadFile("/proc/loadavg")
	if err != nil {
		return 0.0, err
	}
	content := string(contentbytes)
	cols := strings.Fields(content)

	if len(cols) > 2 {
		f, err := strconv.ParseFloat(cols[1], 64)
		if err != nil {
			return 0.0, err
		}
		return f, nil
	}
	return 0.0, fmt.Errorf("cannot fetch loadavg5")
}

func printValue(key string, value *float64, time time.Time) {
	if value != nil {
		fmt.Printf("%s\t%f\t%d\n", key, *value, time.Unix())
	}
}

func outputCPUUsage(cpuUsage []cpuPercentages, now time.Time) {
	for _, u := range cpuUsage {
		printValue("multicore.cpu."+u.CPUName+".user", u.User, now)
		printValue("multicore.cpu."+u.CPUName+".nice", u.Nice, now)
		printValue("multicore.cpu."+u.CPUName+".system", u.System, now)
		printValue("multicore.cpu."+u.CPUName+".idle", u.Idle, now)
		printValue("multicore.cpu."+u.CPUName+".iowait", u.IoWait, now)
		printValue("multicore.cpu."+u.CPUName+".irq", u.Irq, now)
		printValue("multicore.cpu."+u.CPUName+".softirq", u.SoftIrq, now)
		printValue("multicore.cpu."+u.CPUName+".steal", u.Steal, now)
		printValue("multicore.cpu."+u.CPUName+".guest", u.Guest, now)
		printValue("multicore.cpu."+u.CPUName+".guest_nice", u.GuestNice, now)
	}
}

func outputLoadavgPerCore(loadavgPerCore float64, now time.Time) {
	printValue("multicore.loadavg_per_core.loadavg5", &loadavgPerCore, now)
}

func outputDefinitions() {
	fmt.Println("# mackerel-agent-plugin")
	var graphs mp.GraphDef
	graphs.Graphs = graphDef

	b, err := json.Marshal(graphs)
	if err != nil {
		log.Fatalln("OutputDefinitions: ", err)
	}
	fmt.Println(string(b))
}

func outputMulticore(tempFileName string) {
	now := time.Now()

	currentValues, err := collectProcStatValues()
	if err != nil {
		log.Fatalln("collectProcStatValues: ", err)
	}

	savedItem, err := fetchSavedItem(tempFileName)
	saveValues(tempFileName, currentValues, now)
	if err != nil {
		log.Fatalln("fetchLastValues: ", err)
	}

	// maybe first time run
	if savedItem == nil {
		return
	}

	cpuUsage, err := calcCPUUsage(currentValues, now, savedItem)
	if err != nil {
		log.Fatalln("calcCPUUsage: ", err)
	}

	loadavg5, err := fetchLoadavg5()
	if err != nil {
		log.Fatalln("fetchLoadavg5: ", err)
	}
	loadPerCPUCount := loadavg5 / (float64(len(cpuUsage)))

	outputCPUUsage(cpuUsage, now)
	outputLoadavgPerCore(loadPerCPUCount, now)
}

func generateTempfilePath() string {
	dir := os.Getenv("MACKEREL_PLUGIN_WORKDIR")
	if dir == "" {
		dir = os.TempDir()
	}
	return filepath.Join(dir, "mackerel-plugin-multicore")
}

// Do the plugin
func Do() {
	var tempFileName string
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	tempFileName = *optTempfile
	if tempFileName == "" {
		tempFileName = generateTempfilePath()
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		outputDefinitions()
	} else {
		outputMulticore(tempFileName)
	}
}
<commit_msg>use go-mackerel-plugin instead of go-mackerel-plugin-helper<commit_after>package mpmulticore

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	mp "github.com/mackerelio/go-mackerel-plugin"
)

var graphDef = map[string]mp.Graphs{
	"multicore.cpu.#": {
		Label: "MultiCore CPU",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "guest_nice", Label: "guest_nice", Diff: false, Stacked: true},
			{Name: "guest", Label: "guest", Diff: false, Stacked: true},
			{Name: "steal", Label: "steal", Diff: false, Stacked: true},
			{Name: "softirq", Label: "softirq", Diff: false, Stacked: true},
			{Name: "irq", Label: "irq", Diff: false, Stacked: true},
			{Name: "iowait", Label: "ioWait", Diff: false, Stacked: true},
			{Name: "idle", Label: "idle", Diff: false, Stacked: true},
			{Name: "system", Label: "system", Diff: false, Stacked: true},
			{Name: "nice", Label: "nice", Diff: false, Stacked: true},
			{Name: "user", Label: "user", Diff: false, Stacked: true},
		},
	},
	"multicore.loadavg_per_core": {
		Label: "MultiCore loadavg5 per core",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "loadavg5", Label: "loadavg5", Diff: false, Stacked: false},
		},
	},
}

type saveItem struct {
	LastTime       time.Time
	ProcStatsByCPU map[string]procStats
}

type procStats struct {
	User      *uint64 `json:"user"`
	Nice      *uint64 `json:"nice"`
	System    *uint64 `json:"system"`
	Idle      *uint64 `json:"idle"`
	IoWait    *uint64 `json:"iowait"`
	Irq       *uint64 `json:"irq"`
	SoftIrq   *uint64 `json:"softirq"`
	Steal     *uint64 `json:"steal"`
	Guest     *uint64 `json:"guest"`
	GuestNice *uint64 `json:"guest_nice"`
	Total     uint64  `json:"total"`
}

type cpuPercentages struct {
	CPUName   string
	User      *float64
	Nice      *float64
	System    *float64
	Idle      *float64
	IoWait    *float64
	Irq       *float64
	SoftIrq   *float64
	Steal     *float64
	Guest     *float64
	GuestNice *float64
}

func parseProcStat(out io.Reader) (map[string]procStats, error) {
	scanner := bufio.NewScanner(out)
	var result = make(map[string]procStats)
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, "cpu") {
			continue
		}

		fields := strings.Fields(line)
		key := fields[0]
		values := fields[1:]

		// skip total cpu usage
		if key == "cpu" {
			continue
		}

		var stats procStats
		statPtrs := []**uint64{
			&stats.User,
			&stats.Nice,
			&stats.System,
			&stats.Idle,
			&stats.IoWait,
			&stats.Irq,
			&stats.SoftIrq,
			&stats.Steal,
			&stats.Guest,
			&stats.GuestNice,
		}

		for i, valStr := range values {
			val, err := strconv.ParseUint(valStr, 10, 64)
			if err != nil {
				return nil, err
			}
			*statPtrs[i] = &val
			stats.Total += val
		}

		// Since cpustat[CPUTIME_USER] includes cpustat[CPUTIME_GUEST], subtract the duplicated values from total.
		// https://github.com/torvalds/linux/blob/4ec9f7a18/kernel/sched/cputime.c#L151-L158
		if stats.Guest != nil {
			stats.Total -= *stats.Guest
			*stats.User -= *stats.Guest
		}

		// cpustat[CPUTIME_NICE] includes cpustat[CPUTIME_GUEST_NICE]
		if stats.GuestNice != nil {
			stats.Total -= *stats.GuestNice
			*stats.Nice -= *stats.GuestNice
		}

		result[key] = stats
	}
	return result, nil
}

func collectProcStatValues() (map[string]procStats, error) {
	file, err := os.Open("/proc/stat")
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return parseProcStat(file)
}

func saveValues(tempFileName string, values map[string]procStats, now time.Time) error {
	f, err := os.Create(tempFileName)
	if err != nil {
		return err
	}
	defer f.Close()

	s := saveItem{
		LastTime:       now,
		ProcStatsByCPU: values,
	}

	encoder := json.NewEncoder(f)
	err = encoder.Encode(s)
	if err != nil {
		return err
	}

	return nil
}

func fetchSavedItem(tempFileName string) (*saveItem, error) {
	f, err := os.Open(tempFileName)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	defer f.Close()

	var stat saveItem
	decoder := json.NewDecoder(f)
	err = decoder.Decode(&stat)
	if err != nil {
		return nil, err
	}
	return &stat, nil
}

func calcCPUUsage(currentValues map[string]procStats, now time.Time, savedItem *saveItem) ([]cpuPercentages, error) {
	if now.Sub(savedItem.LastTime).Seconds() > 600 {
		return nil, errors.New("Too long duration")
	}

	var result []cpuPercentages
	for name, current := range currentValues {
		last, ok := savedItem.ProcStatsByCPU[name]
		if !ok {
			continue
		}
		if last.Total > current.Total {
			return nil, errors.New("cpu counter has been reset")
		}

		user := calculatePercentage(current.User, last.User, current.Total, last.Total)
		nice := calculatePercentage(current.Nice, last.Nice, current.Total, last.Total)
		system := calculatePercentage(current.System, last.System, current.Total, last.Total)
		idle := calculatePercentage(current.Idle, last.Idle, current.Total, last.Total)
		iowait := calculatePercentage(current.IoWait, last.IoWait, current.Total, last.Total)
		irq := calculatePercentage(current.Irq, last.Irq, current.Total, last.Total)
		softirq := calculatePercentage(current.SoftIrq, last.SoftIrq, current.Total, last.Total)
		steal := calculatePercentage(current.Steal, last.Steal, current.Total, last.Total)
		guest := calculatePercentage(current.Guest, last.Guest, current.Total, last.Total)
		// guest_nice available since Linux 2.6.33 (ref: man proc)
		guestNice := calculatePercentage(current.GuestNice, last.GuestNice, current.Total, last.Total)

		result = append(result, cpuPercentages{
			CPUName:   name,
			User:      user,
			Nice:      nice,
			System:    system,
			Idle:      idle,
			IoWait:    iowait,
			Irq:       irq,
			SoftIrq:   softirq,
			Steal:     steal,
			Guest:     guest,
			GuestNice: guestNice,
		})
	}

	return result, nil
}

func calculatePercentage(currentValue *uint64, lastValue *uint64, currentTotal uint64, lastTotal uint64) *float64 {
	if currentValue == nil || lastValue == nil {
		return nil
	}
	ret := float64(*currentValue-*lastValue) / float64(currentTotal-lastTotal) * 100.0
	return &ret
}

func fetchLoadavg5() (float64, error) {
	contentbytes, err := ioutil.ReadFile("/proc/loadavg")
	if err != nil {
		return 0.0, err
	}
	content := string(contentbytes)
	cols := strings.Fields(content)

	if len(cols) > 2 {
		f, err := strconv.ParseFloat(cols[1], 64)
		if err != nil {
			return 0.0, err
		}
		return f, nil
	}
	return 0.0, fmt.Errorf("cannot fetch loadavg5")
}

func printValue(key string, value *float64, time time.Time) {
	if value != nil {
		fmt.Printf("%s\t%f\t%d\n", key, *value, time.Unix())
	}
}

func outputCPUUsage(cpuUsage []cpuPercentages, now time.Time) {
	for _, u := range cpuUsage {
		printValue("multicore.cpu."+u.CPUName+".user", u.User, now)
		printValue("multicore.cpu."+u.CPUName+".nice", u.Nice, now)
		printValue("multicore.cpu."+u.CPUName+".system", u.System, now)
		printValue("multicore.cpu."+u.CPUName+".idle", u.Idle, now)
		printValue("multicore.cpu."+u.CPUName+".iowait", u.IoWait, now)
		printValue("multicore.cpu."+u.CPUName+".irq", u.Irq, now)
		printValue("multicore.cpu."+u.CPUName+".softirq", u.SoftIrq, now)
		printValue("multicore.cpu."+u.CPUName+".steal", u.Steal, now)
		printValue("multicore.cpu."+u.CPUName+".guest", u.Guest, now)
		printValue("multicore.cpu."+u.CPUName+".guest_nice", u.GuestNice, now)
	}
}

func outputLoadavgPerCore(loadavgPerCore float64, now time.Time) {
	printValue("multicore.loadavg_per_core.loadavg5", &loadavgPerCore, now)
}

func outputDefinitions() {
	fmt.Println("# mackerel-agent-plugin")
	var graphs mp.GraphDef
	graphs.Graphs = graphDef

	b, err := json.Marshal(graphs)
	if err != nil {
		log.Fatalln("OutputDefinitions: ", err)
	}
	fmt.Println(string(b))
}

func outputMulticore(tempFileName string) {
	now := time.Now()

	currentValues, err := collectProcStatValues()
	if err != nil {
		log.Fatalln("collectProcStatValues: ", err)
	}

	savedItem, err := fetchSavedItem(tempFileName)
	saveValues(tempFileName, currentValues, now)
	if err != nil {
		log.Fatalln("fetchLastValues: ", err)
	}

	// maybe first time run
	if savedItem == nil {
		return
	}

	cpuUsage, err := calcCPUUsage(currentValues, now, savedItem)
	if err != nil {
		log.Fatalln("calcCPUUsage: ", err)
	}

	loadavg5, err := fetchLoadavg5()
	if err != nil {
		log.Fatalln("fetchLoadavg5: ", err)
	}
	loadPerCPUCount := loadavg5 / (float64(len(cpuUsage)))

	outputCPUUsage(cpuUsage, now)
	outputLoadavgPerCore(loadPerCPUCount, now)
}

func generateTempfilePath() string {
	dir := os.Getenv("MACKEREL_PLUGIN_WORKDIR")
	if dir == "" {
		dir = os.TempDir()
	}
	return filepath.Join(dir, "mackerel-plugin-multicore")
}

// Do the plugin
func Do() {
	var tempFileName string
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	tempFileName = *optTempfile
	if tempFileName == "" {
		tempFileName = generateTempfilePath()
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		outputDefinitions()
	} else {
		outputMulticore(tempFileName)
	}
}
<|endoftext|>


<commit_before>package main

// +build ignore

import (
	"fmt"
	"github.com/skelterjohn/geom"
	"github.com/skelterjohn/go.uik"
	"github.com/skelterjohn/go.uik/layouts"
	"github.com/skelterjohn/go.uik/widgets"
	"github.com/kirillDanshin/go-wde"
	_ "github.com/kirillDanshin/go-wde/glfw3"
	"image/color"
)

func main() {
	go uikplay()
	wde.Run()
}

func uikplay() {

	w, err := uik.NewWindow(nil, 480, 320)
	if err != nil {
		fmt.Println(err)
		return
	}
	w.W.SetTitle("go.uik")

	gcfg, err := layouts.ParseGridConfig(`
{
	"Components": {
		"radio": {
			"GridX": 0,
			"GridY": 0,
			"AnchorLeft": true,
			"AnchorTop": true
		},
		"label": {
			"GridX": 1,
			"GridY": 0,
			"AnchorRight": true,
			"AnchorTop": true
		}
	}
}
		`)
	if err != nil {
		fmt.Println(err)
		return
	}

	ge := layouts.NewGridEngine(gcfg)
	g := layouts.NewLayouter(ge)

	rg := widgets.NewRadio([]string{"bread", "cake", "beheadings"})
	ge.AddName("radio", &rg.Block)

	l := widgets.NewLabel(geom.Coord{100, 30}, widgets.LabelConfig{"text", 14, color.Black})
	ge.AddName("label", &layouts.NewPadBox(layouts.PadConfig{Right: 10}, &l.Block).Block)

	selLis := make(widgets.SelectionListener, 1)
	rg.AddSelectionListener <- selLis

	w.SetPane(&g.Block)

	w.Show()

	done := make(chan interface{}, 1)
	isDone := func(e interface{}) (accept, done bool) {
		_, accept = e.(uik.CloseEvent)
		done = accept
		return
	}
	w.Block.Subscribe <- uik.Subscription{isDone, done}

loop:
	for {
		select {
		case sel := <-selLis:
			l.SetConfig(widgets.LabelConfig{
				Text:     fmt.Sprintf("Clicked option %d, %q", sel.Index, sel.Option),
				FontSize: 14,
				Color:    color.Black,
			})
		case <-done:
			break loop
		}
	}

	w.W.Close()

	wde.Stop()
}
<commit_msg>migrate uik link to my fork<commit_after>package main

// +build ignore

import (
	"fmt"
	"image/color"

	"github.com/kirillDanshin/go-wde"
	_ "github.com/kirillDanshin/go-wde/glfw3"
	"github.com/kirillDanshin/go.uik"
	"github.com/kirillDanshin/go.uik/layouts"
	"github.com/kirillDanshin/go.uik/widgets"
	"github.com/skelterjohn/geom"
)

func main() {
	go uikplay()
	wde.Run()
}

func uikplay() {

	w, err := uik.NewWindow(nil, 480, 320)
	if err != nil {
		fmt.Println(err)
		return
	}
	w.W.SetTitle("go.uik")

	gcfg, err := layouts.ParseGridConfig(`
{
	"Components": {
		"radio": {
			"GridX": 0,
			"GridY": 0,
			"AnchorLeft": true,
			"AnchorTop": true
		},
		"label": {
			"GridX": 1,
			"GridY": 0,
			"AnchorRight": true,
			"AnchorTop": true
		}
	}
}
		`)
	if err != nil {
		fmt.Println(err)
		return
	}

	ge := layouts.NewGridEngine(gcfg)
	g := layouts.NewLayouter(ge)

	rg := widgets.NewRadio([]string{"bread", "cake", "beheadings"})
	ge.AddName("radio", &rg.Block)

	l := widgets.NewLabel(geom.Coord{100, 30}, widgets.LabelConfig{"text", 14, color.Black})
	ge.AddName("label", &layouts.NewPadBox(layouts.PadConfig{Right: 10}, &l.Block).Block)

	selLis := make(widgets.SelectionListener, 1)
	rg.AddSelectionListener <- selLis

	w.SetPane(&g.Block)

	w.Show()

	done := make(chan interface{}, 1)
	isDone := func(e interface{}) (accept, done bool) {
		_, accept = e.(uik.CloseEvent)
		done = accept
		return
	}
	w.Block.Subscribe <- uik.Subscription{isDone, done}

loop:
	for {
		select {
		case sel := <-selLis:
			l.SetConfig(widgets.LabelConfig{
				Text:     fmt.Sprintf("Clicked option %d, %q", sel.Index, sel.Option),
				FontSize: 14,
				Color:    color.Black,
			})
		case <-done:
			break loop
		}
	}

	w.W.Close()

	wde.Stop()
}
<|endoftext|>


<commit_before>package httpserver

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyfile"
	"github.com/mholt/caddy/caddytls"
)

const serverType = "http"

func init() {
	flag.StringVar(&Host, "host", DefaultHost, "Default host")
	flag.StringVar(&Port, "port", DefaultPort, "Default port")
	flag.StringVar(&Root, "root", DefaultRoot, "Root path of default site")
	flag.DurationVar(&GracefulTimeout, "grace", 5*time.Second, "Maximum duration of graceful shutdown") // TODO
	flag.BoolVar(&HTTP2, "http2", true, "Use HTTP/2")
	flag.BoolVar(&QUIC, "quic", false, "Use experimental QUIC")

	caddy.RegisterServerType(serverType, caddy.ServerType{
		Directives: directives,
		DefaultInput: func() caddy.Input {
			if Port == DefaultPort && Host != "" {
				// by leaving the port blank in this case we give auto HTTPS
				// a chance to set the port to 443 for us
				return caddy.CaddyfileInput{
					Contents:       []byte(fmt.Sprintf("%s\nroot %s", Host, Root)),
					ServerTypeName: serverType,
				}
			}
			return caddy.CaddyfileInput{
				Contents:       []byte(fmt.Sprintf("%s:%s\nroot %s", Host, Port, Root)),
				ServerTypeName: serverType,
			}
		},
		NewContext: newContext,
	})
	caddy.RegisterCaddyfileLoader("short", caddy.LoaderFunc(shortCaddyfileLoader))
	caddy.RegisterParsingCallback(serverType, "tls", activateHTTPS)
	caddytls.RegisterConfigGetter(serverType, func(c *caddy.Controller) *caddytls.Config { return GetConfig(c).TLS })
}

func newContext() caddy.Context {
	return &httpContext{keysToSiteConfigs: make(map[string]*SiteConfig)}
}

type httpContext struct {
	// keysToSiteConfigs maps an address at the top of a
	// server block (a "key") to its SiteConfig. Not all
	// SiteConfigs will be represented here, only ones
	// that appeared in the Caddyfile.
	keysToSiteConfigs map[string]*SiteConfig

	// siteConfigs is the master list of all site configs.
	siteConfigs []*SiteConfig
}

func (h *httpContext) saveConfig(key string, cfg *SiteConfig) {
	h.siteConfigs = append(h.siteConfigs, cfg)
	h.keysToSiteConfigs[key] = cfg
}

// InspectServerBlocks make sure that everything checks out before
// executing directives and otherwise prepares the directives to
// be parsed and executed.
func (h *httpContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
	// For each address in each server block, make a new config
	for _, sb := range serverBlocks {
		for _, key := range sb.Keys {
			key = strings.ToLower(key)
			if _, dup := h.keysToSiteConfigs[key]; dup {
				return serverBlocks, fmt.Errorf("duplicate site address: %s", key)
			}
			addr, err := standardizeAddress(key)
			if err != nil {
				return serverBlocks, err
			}

			// Fill in address components from command line so that middleware
			// have access to the correct information during setup
			if addr.Host == "" && Host != DefaultHost {
				addr.Host = Host
			}
			if addr.Port == "" && Port != DefaultPort {
				addr.Port = Port
			}

			// Save the config to our master list, and key it for lookups
			cfg := &SiteConfig{
				Addr:        addr,
				Root:        Root,
				TLS:         &caddytls.Config{Hostname: addr.Host},
				HiddenFiles: []string{sourceFile},
			}
			h.saveConfig(key, cfg)
		}
	}

	// For sites that have gzip (which gets chained in
	// before the error handler) we should ensure that the
	// errors directive also appears so error pages aren't
	// written after the gzip writer is closed. See #616.
	for _, sb := range serverBlocks {
		_, hasGzip := sb.Tokens["gzip"]
		_, hasErrors := sb.Tokens["errors"]
		if hasGzip && !hasErrors {
			sb.Tokens["errors"] = []caddyfile.Token{{Text: "errors"}}
		}
	}

	return serverBlocks, nil
}

// MakeServers uses the newly-created siteConfigs to
// create and return a list of server instances.
func (h *httpContext) MakeServers() ([]caddy.Server, error) {
	// make sure TLS is disabled for explicitly-HTTP sites
	// (necessary when HTTP address shares a block containing tls)
	for _, cfg := range h.siteConfigs {
		if !cfg.TLS.Enabled {
			continue
		}
		if cfg.Addr.Port == "80" || cfg.Addr.Scheme == "http" {
			cfg.TLS.Enabled = false
			log.Printf("[WARNING] TLS disabled for %s", cfg.Addr)
		} else if cfg.Addr.Scheme == "" {
			// set scheme to https ourselves, since TLS is enabled
			// and it was not explicitly set to something else. this
			// makes it appear as "https" when we print the list of
			// running sites; otherwise "http" would be assumed which
			// is incorrect for this site.
			cfg.Addr.Scheme = "https"
		}
		if cfg.Addr.Port == "" {
			// this is vital, otherwise the function call below that
			// sets the listener address will use the default port
			// instead of 443 because it doesn't know about TLS.
			cfg.Addr.Port = "443"
		}
	}

	// we must map (group) each config to a bind address
	groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
	if err != nil {
		return nil, err
	}

	// then we create a server for each group
	var servers []caddy.Server
	for addr, group := range groups {
		s, err := NewServer(addr, group)
		if err != nil {
			return nil, err
		}
		servers = append(servers, s)
	}

	return servers, nil
}

// GetConfig gets the SiteConfig that corresponds to c.
// If none exist (should only happen in tests), then a
// new, empty one will be created.
func GetConfig(c *caddy.Controller) *SiteConfig {
	ctx := c.Context().(*httpContext)
	if cfg, ok := ctx.keysToSiteConfigs[c.Key]; ok {
		return cfg
	}
	// we should only get here during tests because directive
	// actions typically skip the server blocks where we make
	// the configs
	ctx.saveConfig(c.Key, &SiteConfig{Root: Root, TLS: new(caddytls.Config)})
	return GetConfig(c)
}

// shortCaddyfileLoader loads a Caddyfile if positional arguments are
// detected, or, in other words, if un-named arguments are provided to
// the program. A "short Caddyfile" is one in which each argument
// is a line of the Caddyfile. The default host and port are prepended
// according to the Host and Port values.
func shortCaddyfileLoader(serverType string) (caddy.Input, error) {
	if flag.NArg() > 0 && serverType == "http" {
		confBody := fmt.Sprintf("%s:%s\n%s", Host, Port, strings.Join(flag.Args(), "\n"))
		return caddy.CaddyfileInput{
			Contents:       []byte(confBody),
			Filepath:       "args",
			ServerTypeName: serverType,
		}, nil
	}
	return nil, nil
}

// groupSiteConfigsByListenAddr groups site configs by their listen
// (bind) address, so sites that use the same listener can be served
// on the same server instance. The return value maps the listen
// address (what you pass into net.Listen) to the list of site configs.
// This function does NOT vet the configs to ensure they are compatible.
func groupSiteConfigsByListenAddr(configs []*SiteConfig) (map[string][]*SiteConfig, error) {
	groups := make(map[string][]*SiteConfig)

	for _, conf := range configs {
		if caddy.IsLoopback(conf.Addr.Host) && conf.ListenHost == "" {
			// special case: one would not expect a site served
			// at loopback to be connected to from the outside.
			conf.ListenHost = conf.Addr.Host
		}
		if conf.Addr.Port == "" {
			conf.Addr.Port = Port
		}
		addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.ListenHost, conf.Addr.Port))
		if err != nil {
			return nil, err
		}
		addrstr := addr.String()
		groups[addrstr] = append(groups[addrstr], conf)
	}

	return groups, nil
}

// AddMiddleware adds a middleware to a site's middleware stack.
func (sc *SiteConfig) AddMiddleware(m Middleware) {
	sc.middleware = append(sc.middleware, m)
}

// Address represents a site address. It contains
// the original input value, and the component
// parts of an address. The component parts may be
// updated to the correct values as setup proceeds,
// but the original value should never be changed.
type Address struct {
	Original, Scheme, Host, Port, Path string
}

// String returns a human-friendly print of the address.
func (a Address) String() string {
	if a.Host == "" && a.Port == "" {
		return ""
	}
	scheme := a.Scheme
	if scheme == "" {
		if a.Port == "443" {
			scheme = "https"
		} else {
			scheme = "http"
		}
	}
	s := scheme
	if s != "" {
		s += "://"
	}
	s += a.Host
	if a.Port != "" &&
		((scheme == "https" && a.Port != "443") ||
			(scheme == "http" && a.Port != "80")) {
		s += ":" + a.Port
	}
	if a.Path != "" {
		s += a.Path
	}
	return s
}

// VHost returns a sensible concatenation of Host:Port/Path from a.
// It's basically the a.Original but without the scheme.
func (a Address) VHost() string {
	if idx := strings.Index(a.Original, "://"); idx > -1 {
		return a.Original[idx+3:]
	}
	return a.Original
}

// standardizeAddress parses an address string into a structured format with separate
// scheme, host, and port portions, as well as the original input string.
func standardizeAddress(str string) (Address, error) {
	input := str

	// Split input into components (prepend with // to assert host by default)
	if !strings.Contains(str, "//") {
		str = "//" + str
	}
	u, err := url.Parse(str)
	if err != nil {
		return Address{}, err
	}

	// separate host and port
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		host, port, err = net.SplitHostPort(u.Host + ":")
		if err != nil {
			host = u.Host
		}
	}

	// see if we can set port based off scheme
	if port == "" {
		if u.Scheme == "http" {
			port = "80"
		} else if u.Scheme == "https" {
			port = "443"
		}
	}

	// repeated or conflicting scheme is confusing, so error
	if u.Scheme != "" && (port == "http" || port == "https") {
		return Address{}, fmt.Errorf("[%s] scheme specified twice in address", input)
	}

	// error if scheme and port combination violate convention
	if (u.Scheme == "http" && port == "443") || (u.Scheme == "https" && port == "80") {
		return Address{}, fmt.Errorf("[%s] scheme and port violate convention", input)
	}

	// standardize http and https ports to their respective port numbers
	if port == "http" {
		u.Scheme = "http"
		port = "80"
	} else if port == "https" {
		u.Scheme = "https"
		port = "443"
	}

	return Address{Original: input, Scheme: u.Scheme, Host: host, Port: port, Path: u.Path}, err
}

// directives is the list of all directives known to exist for the
// http server type, including non-standard (3rd-party) directives.
// The ordering of this list is important.
var directives = []string{
	// primitive actions that set up the fundamental vitals of each config
	"root",
	"tls",
	"bind",

	// services/utilities, or other directives that don't necessarily inject handlers
	"startup",
	"shutdown",
	"realip", // github.com/captncraig/caddy-realip
	"git",    // github.com/abiosoft/caddy-git

	// directives that add middleware to the stack
	"log",
	"gzip",
	"errors",
	"minify",   // github.com/hacdias/caddy-minify
	"ipfilter", // github.com/pyed/ipfilter
	"search",   // github.com/pedronasser/caddy-search
	"header",
	"cors", // github.com/captncraig/cors/caddy
	"rewrite",
	"redir",
	"ext",
	"mime",
	"basicauth",
	"jwt",    // github.com/BTBurke/caddy-jwt
	"jsonp",  // github.com/pschlump/caddy-jsonp
	"upload", // blitznote.com/src/caddy.upload
	"internal",
	"pprof",
	"expvar",
	"proxy",
	"fastcgi",
	"websocket",
	"markdown",
	"templates",
	"browse",
	"hugo",        // github.com/hacdias/caddy-hugo
	"filemanager", // github.com/hacdias/caddy-filemanager
	"mailout",     // github.com/SchumacherFM/mailout
	"prometheus",  // github.com/miekg/caddy-prometheus
}

const (
	// DefaultHost is the default host.
	DefaultHost = ""
	// DefaultPort is the default port.
	DefaultPort = "2015"
	// DefaultRoot is the default root folder.
	DefaultRoot = "."
)

// These "soft defaults" are configurable by
// command line flags, etc.
var (
	// Root is the site root
	Root = DefaultRoot

	// Host is the site host
	Host = DefaultHost

	// Port is the site port
	Port = DefaultPort

	// GracefulTimeout is the maximum duration of a graceful shutdown.
	GracefulTimeout time.Duration

	// HTTP2 indicates whether HTTP2 is enabled or not.
	HTTP2 bool

	// QUIC indicates whether QUIC is enabled or not.
	QUIC bool
)
<commit_msg>Change hugo and filemanager order<commit_after>package httpserver

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyfile"
	"github.com/mholt/caddy/caddytls"
)

const serverType = "http"

func init() {
	flag.StringVar(&Host, "host", DefaultHost, "Default host")
	flag.StringVar(&Port, "port", DefaultPort, "Default port")
	flag.StringVar(&Root, "root", DefaultRoot, "Root path of default site")
	flag.DurationVar(&GracefulTimeout, "grace", 5*time.Second, "Maximum duration of graceful shutdown") // TODO
	flag.BoolVar(&HTTP2, "http2", true, "Use HTTP/2")
	flag.BoolVar(&QUIC, "quic", false, "Use experimental QUIC")

	caddy.RegisterServerType(serverType, caddy.ServerType{
		Directives: directives,
		DefaultInput: func() caddy.Input {
			if Port == DefaultPort && Host != "" {
				// by leaving the port blank in this case we give auto HTTPS
				// a chance to set the port to 443 for us
				return caddy.CaddyfileInput{
					Contents:       []byte(fmt.Sprintf("%s\nroot %s", Host, Root)),
					ServerTypeName: serverType,
				}
			}
			return caddy.CaddyfileInput{
				Contents:       []byte(fmt.Sprintf("%s:%s\nroot %s", Host, Port, Root)),
				ServerTypeName: serverType,
			}
		},
		NewContext: newContext,
	})
	caddy.RegisterCaddyfileLoader("short", caddy.LoaderFunc(shortCaddyfileLoader))
	caddy.RegisterParsingCallback(serverType, "tls", activateHTTPS)
	caddytls.RegisterConfigGetter(serverType, func(c *caddy.Controller) *caddytls.Config { return GetConfig(c).TLS })
}

func newContext() caddy.Context {
	return &httpContext{keysToSiteConfigs: make(map[string]*SiteConfig)}
}

type httpContext struct {
	// keysToSiteConfigs maps an address at the top of a
	// server block (a "key") to its SiteConfig. Not all
	// SiteConfigs will be represented here, only ones
	// that appeared in the Caddyfile.
	keysToSiteConfigs map[string]*SiteConfig

	// siteConfigs is the master list of all site configs.
	siteConfigs []*SiteConfig
}

func (h *httpContext) saveConfig(key string, cfg *SiteConfig) {
	h.siteConfigs = append(h.siteConfigs, cfg)
	h.keysToSiteConfigs[key] = cfg
}

// InspectServerBlocks make sure that everything checks out before
// executing directives and otherwise prepares the directives to
// be parsed and executed.
func (h *httpContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
	// For each address in each server block, make a new config
	for _, sb := range serverBlocks {
		for _, key := range sb.Keys {
			key = strings.ToLower(key)
			if _, dup := h.keysToSiteConfigs[key]; dup {
				return serverBlocks, fmt.Errorf("duplicate site address: %s", key)
			}
			addr, err := standardizeAddress(key)
			if err != nil {
				return serverBlocks, err
			}

			// Fill in address components from command line so that middleware
			// have access to the correct information during setup
			if addr.Host == "" && Host != DefaultHost {
				addr.Host = Host
			}
			if addr.Port == "" && Port != DefaultPort {
				addr.Port = Port
			}

			// Save the config to our master list, and key it for lookups
			cfg := &SiteConfig{
				Addr:        addr,
				Root:        Root,
				TLS:         &caddytls.Config{Hostname: addr.Host},
				HiddenFiles: []string{sourceFile},
			}
			h.saveConfig(key, cfg)
		}
	}

	// For sites that have gzip (which gets chained in
	// before the error handler) we should ensure that the
	// errors directive also appears so error pages aren't
	// written after the gzip writer is closed. See #616.
	for _, sb := range serverBlocks {
		_, hasGzip := sb.Tokens["gzip"]
		_, hasErrors := sb.Tokens["errors"]
		if hasGzip && !hasErrors {
			sb.Tokens["errors"] = []caddyfile.Token{{Text: "errors"}}
		}
	}

	return serverBlocks, nil
}

// MakeServers uses the newly-created siteConfigs to
// create and return a list of server instances.
func (h *httpContext) MakeServers() ([]caddy.Server, error) {
	// make sure TLS is disabled for explicitly-HTTP sites
	// (necessary when HTTP address shares a block containing tls)
	for _, cfg := range h.siteConfigs {
		if !cfg.TLS.Enabled {
			continue
		}
		if cfg.Addr.Port == "80" || cfg.Addr.Scheme == "http" {
			cfg.TLS.Enabled = false
			log.Printf("[WARNING] TLS disabled for %s", cfg.Addr)
		} else if cfg.Addr.Scheme == "" {
			// set scheme to https ourselves, since TLS is enabled
			// and it was not explicitly set to something else. this
			// makes it appear as "https" when we print the list of
			// running sites; otherwise "http" would be assumed which
			// is incorrect for this site.
			cfg.Addr.Scheme = "https"
		}
		if cfg.Addr.Port == "" {
			// this is vital, otherwise the function call below that
			// sets the listener address will use the default port
			// instead of 443 because it doesn't know about TLS.
			cfg.Addr.Port = "443"
		}
	}

	// we must map (group) each config to a bind address
	groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
	if err != nil {
		return nil, err
	}

	// then we create a server for each group
	var servers []caddy.Server
	for addr, group := range groups {
		s, err := NewServer(addr, group)
		if err != nil {
			return nil, err
		}
		servers = append(servers, s)
	}

	return servers, nil
}

// GetConfig gets the SiteConfig that corresponds to c.
// If none exist (should only happen in tests), then a
// new, empty one will be created.
func GetConfig(c *caddy.Controller) *SiteConfig {
	ctx := c.Context().(*httpContext)
	if cfg, ok := ctx.keysToSiteConfigs[c.Key]; ok {
		return cfg
	}
	// we should only get here during tests because directive
	// actions typically skip the server blocks where we make
	// the configs
	ctx.saveConfig(c.Key, &SiteConfig{Root: Root, TLS: new(caddytls.Config)})
	return GetConfig(c)
}

// shortCaddyfileLoader loads a Caddyfile if positional arguments are
// detected, or, in other words, if un-named arguments are provided to
// the program. A "short Caddyfile" is one in which each argument
// is a line of the Caddyfile. The default host and port are prepended
// according to the Host and Port values.
func shortCaddyfileLoader(serverType string) (caddy.Input, error) {
	if flag.NArg() > 0 && serverType == "http" {
		confBody := fmt.Sprintf("%s:%s\n%s", Host, Port, strings.Join(flag.Args(), "\n"))
		return caddy.CaddyfileInput{
			Contents:       []byte(confBody),
			Filepath:       "args",
			ServerTypeName: serverType,
		}, nil
	}
	return nil, nil
}

// groupSiteConfigsByListenAddr groups site configs by their listen
// (bind) address, so sites that use the same listener can be served
// on the same server instance. The return value maps the listen
// address (what you pass into net.Listen) to the list of site configs.
// This function does NOT vet the configs to ensure they are compatible.
func groupSiteConfigsByListenAddr(configs []*SiteConfig) (map[string][]*SiteConfig, error) {
	groups := make(map[string][]*SiteConfig)

	for _, conf := range configs {
		if caddy.IsLoopback(conf.Addr.Host) && conf.ListenHost == "" {
			// special case: one would not expect a site served
			// at loopback to be connected to from the outside.
			conf.ListenHost = conf.Addr.Host
		}
		if conf.Addr.Port == "" {
			conf.Addr.Port = Port
		}
		addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.ListenHost, conf.Addr.Port))
		if err != nil {
			return nil, err
		}
		addrstr := addr.String()
		groups[addrstr] = append(groups[addrstr], conf)
	}

	return groups, nil
}

// AddMiddleware adds a middleware to a site's middleware stack.
func (sc *SiteConfig) AddMiddleware(m Middleware) {
	sc.middleware = append(sc.middleware, m)
}

// Address represents a site address. It contains
// the original input value, and the component
// parts of an address. The component parts may be
// updated to the correct values as setup proceeds,
// but the original value should never be changed.
type Address struct {
	Original, Scheme, Host, Port, Path string
}

// String returns a human-friendly print of the address.
func (a Address) String() string {
	if a.Host == "" && a.Port == "" {
		return ""
	}
	scheme := a.Scheme
	if scheme == "" {
		if a.Port == "443" {
			scheme = "https"
		} else {
			scheme = "http"
		}
	}
	s := scheme
	if s != "" {
		s += "://"
	}
	s += a.Host
	if a.Port != "" &&
		((scheme == "https" && a.Port != "443") ||
			(scheme == "http" && a.Port != "80")) {
		s += ":" + a.Port
	}
	if a.Path != "" {
		s += a.Path
	}
	return s
}

// VHost returns a sensible concatenation of Host:Port/Path from a.
// It's basically the a.Original but without the scheme.
func (a Address) VHost() string {
	if idx := strings.Index(a.Original, "://"); idx > -1 {
		return a.Original[idx+3:]
	}
	return a.Original
}

// standardizeAddress parses an address string into a structured format with separate
// scheme, host, and port portions, as well as the original input string.
func standardizeAddress(str string) (Address, error) {
	input := str

	// Split input into components (prepend with // to assert host by default)
	if !strings.Contains(str, "//") {
		str = "//" + str
	}
	u, err := url.Parse(str)
	if err != nil {
		return Address{}, err
	}

	// separate host and port
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		host, port, err = net.SplitHostPort(u.Host + ":")
		if err != nil {
			host = u.Host
		}
	}

	// see if we can set port based off scheme
	if port == "" {
		if u.Scheme == "http" {
			port = "80"
		} else if u.Scheme == "https" {
			port = "443"
		}
	}

	// repeated or conflicting scheme is confusing, so error
	if u.Scheme != "" && (port == "http" || port == "https") {
		return Address{}, fmt.Errorf("[%s] scheme specified twice in address", input)
	}

	// error if scheme and port combination violate convention
	if (u.Scheme == "http" && port == "443") || (u.Scheme == "https" && port == "80") {
		return Address{}, fmt.Errorf("[%s] scheme and port violate convention", input)
	}

	// standardize http and https ports to their respective port numbers
	if port == "http" {
		u.Scheme = "http"
		port = "80"
	} else if port == "https" {
		u.Scheme = "https"
		port = "443"
	}

	return Address{Original: input, Scheme: u.Scheme, Host: host, Port: port, Path: u.Path}, err
}

// directives is the list of all directives known to exist for the
// http server type, including non-standard (3rd-party) directives.
// The ordering of this list is important.
var directives = []string{
	// primitive actions that set up the fundamental vitals of each config
	"root",
	"tls",
	"bind",

	// services/utilities, or other directives that don't necessarily inject handlers
	"startup",
	"shutdown",
	"realip", // github.com/captncraig/caddy-realip
	"git",    // github.com/abiosoft/caddy-git

	// directives that add middleware to the stack
	"log",
	"gzip",
	"errors",
	"minify",   // github.com/hacdias/caddy-minify
	"ipfilter", // github.com/pyed/ipfilter
	"search",   // github.com/pedronasser/caddy-search
	"header",
	"cors", // github.com/captncraig/cors/caddy
	"rewrite",
	"redir",
	"ext",
	"mime",
	"basicauth",
	"jwt",    // github.com/BTBurke/caddy-jwt
	"jsonp",  // github.com/pschlump/caddy-jsonp
	"upload", // blitznote.com/src/caddy.upload
	"internal",
	"pprof",
	"expvar",
	"proxy",
	"fastcgi",
	"websocket",
	"markdown",
	"templates",
	"browse",
	"filemanager", // github.com/hacdias/caddy-filemanager
	"hugo",        // github.com/hacdias/caddy-hugo
	"mailout",     // github.com/SchumacherFM/mailout
	"prometheus",  // github.com/miekg/caddy-prometheus
}

const (
	// DefaultHost is the default host.
	DefaultHost = ""
	// DefaultPort is the default port.
	DefaultPort = "2015"
	// DefaultRoot is the default root folder.
	DefaultRoot = "."
)

// These "soft defaults" are configurable by
// command line flags, etc.
var (
	// Root is the site root
	Root = DefaultRoot

	// Host is the site host
	Host = DefaultHost

	// Port is the site port
	Port = DefaultPort

	// GracefulTimeout is the maximum duration of a graceful shutdown.
	GracefulTimeout time.Duration

	// HTTP2 indicates whether HTTP2 is enabled or not.
	HTTP2 bool

	// QUIC indicates whether QUIC is enabled or not.
	QUIC bool
)
<|endoftext|>


<commit_before>package api_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/t3hmrman/casgo/cas"
	"testing"
	"net/http/httptest"
)

// Testing globals for HTTP tests
var testHTTPServer *httptest.Server
var testCASConfig map[string]string
var testCASServer *cas.CAS

func TestCasgoAPI(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "CasGo API Suite")
}

var _ = BeforeSuite(func() {
	// Setup CAS server & DB
	testCASConfig, _ = cas.NewCASServerConfig(map[string]string{
		"companyName":        "Casgo Testing Company",
		"dbName":             "casgo_test",
		"templatesDirectory": "../templates",
	})
	testCASServer, _ = cas.NewCASServer(testCASConfig)
	testCASServer.SetupDb()

	// Setup http test server
	testHTTPServer = httptest.NewServer(testCASServer.ServeMux)

	// Load database fixtures
	testCASServer.Db.LoadJSONFixture(
		testCASServer.Db.GetDbName(),
		testCASServer.Db.GetServicesTableName(),
		"../../fixtures/services.json",
	)
	testCASServer.Db.LoadJSONFixture(
		testCASServer.Db.GetDbName(),
		testCASServer.Db.GetUsersTableName(),
		"../../fixtures/users.json",
	)

})

var _ = AfterSuite(func() {
	testHTTPServer.Close()
	testCASServer.TeardownDb()
})
<commit_msg>Add code to API suite to load api_keys fixture<commit_after>package api_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/t3hmrman/casgo/cas"
	"testing"
	"net/http/httptest"
)

// Testing globals for HTTP tests
var testHTTPServer *httptest.Server
var testCASConfig map[string]string
var testCASServer *cas.CAS

func TestCasgoAPI(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "CasGo API Suite")
}

var _ = BeforeSuite(func() {
	// Setup CAS server & DB
	testCASConfig, _ = cas.NewCASServerConfig(map[string]string{
		"companyName":        "Casgo Testing Company",
		"dbName":             "casgo_test",
		"templatesDirectory": "../templates",
	})
	testCASServer, _ = cas.NewCASServer(testCASConfig)
	testCASServer.SetupDb()

	// Setup http test server
	testHTTPServer = httptest.NewServer(testCASServer.ServeMux)

	// Load database fixtures
	testCASServer.Db.LoadJSONFixture(
		testCASServer.Db.GetDbName(),
		testCASServer.Db.GetServicesTableName(),
		"../../fixtures/services.json",
	)
	testCASServer.Db.LoadJSONFixture(
		testCASServer.Db.GetDbName(),
		testCASServer.Db.GetUsersTableName(),
		"../../fixtures/users.json",
	)
	testCASServer.Db.LoadJSONFixture(
		testCASServer.Db.GetDbName(),
		testCASServer.Db.GetApiKeysTableName(),
		"../../fixtures/api_keys.json",
	)

})

var _ = AfterSuite(func() {
	testHTTPServer.Close()
	testCASServer.TeardownDb()
})
<|endoftext|>


<commit_before>package fnet

type FrameConn interface {
	FrameSize() int

	// Stop gracefully stops the FrameConn.
	Stop()

	// SendFrame sends a bounded-size frame over the connection.
	// PRE: b :->[] bs, len(bs) = FrameSize
	// RET: b :->[] xs, len(xs) = FrameSize
	// EFF: if err = nil then SendFrame(bs) else (SendFrame(xs) OR NoEffects)
	SendFrame(b []byte) error // only frames of valid size or less

	// RecvFrame receives a bounded-size fram over the connection
	// PRE: b :->[] mm, len(mm) = FrameSize.
	// RET: b :->[] bs, len(bs) = FrameSize
	// EFF: if err = nil then RecvFrame(firstn n received) else (RecvFrame(firstn n bs) OR NoEffects)
	RecvFrame(b []byte) (n int, err error)
}
<commit_msg>frameconn doc update<commit_after>package fnet

type FrameConn interface {
	FrameSize() int

	// Stop gracefully stops the FrameConn.
	Stop()

	// SendFrame sends a bounded-size frame over the connection.
	// PRE: b :->[] bs, len(bs) = FrameSize
	// RET: b :->[] xs, len(xs) = FrameSize
	// EFF: if err = nil then SendFrame(bs) else (SendFrame(xs) OR NoEffects)
	SendFrame(b []byte) error // only frames of valid size or less

	// RecvFrame receives a bounded-size fram over the connection
	// PRE: b :->[] mm, len(mm) = FrameSize.
	// RET: b :->[] bs, len(bs) = FrameSize
	// EFF: if err = nil then RecvFrame(bs) else (RecvFrame(bs) OR NoEffects)
	RecvFrame(b []byte) (n int, err error)
}
<|endoftext|>


<commit_before>package forecast

import (
	"bytes"
	"fmt"
	"math"
	"strings"
	"time"

	"github.com/jessfraz/weather/geocode"
	"github.com/jessfraz/weather/icons"
	"github.com/mitchellh/colorstring"
)

// UnitMeasures are the location specific terms for weather data.
type UnitMeasures struct {
	Degrees       string
	Speed         string
	Length        string
	Precipitation string
}

var (
	// UnitFormats describe each regions UnitMeasures.
	UnitFormats = map[string]UnitMeasures{
		"us": {
			Degrees:       "°F",
			Speed:         "mph",
			Length:        "miles",
			Precipitation: "in/hr",
		},
		"si": {
			Degrees:       "°C",
			Speed:         "m/s",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		"ca": {
			Degrees:       "°C",
			Speed:         "km/h",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		// deprecated, use "uk2" in stead
		"uk": {
			Degrees:       "°C",
			Speed:         "mph",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		"uk2": {
			Degrees:       "°C",
			Speed:         "mph",
			Length:        "miles",
			Precipitation: "mm/h",
		},
	}
	// Directions contain all the combinations of N,S,E,W
	Directions = []string{
		"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW",
	}
)

func epochFormat(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("January 2 at 3:04pm MST")
}

func epochFormatDate(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("January 2 (Monday)")
}

func epochFormatTime(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("3:04pm MST")
}

func epochFormatHour(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	s := epochTime.Format("3pm")
	s = s[:len(s)-1]
	if len(s) == 2 {
		s += " "
	}
	return s
}

func getIcon(iconStr string) (icon string, err error) {
	color := "blue"
	// steralize the icon string name
	iconStr = strings.Replace(strings.Replace(iconStr, "-", "", -1), "_", "", -1)

	switch iconStr {
	case "clear":
		icon = icons.Clear
	case "clearday":
		color = "yellow"
		icon = icons.Clearday
	case "clearnight":
		color = "light_yellow"
		icon = icons.Clearnight
	case "clouds":
		icon = icons.Clouds
	case "cloudy":
		icon = icons.Cloudy
	case "cloudsnight":
		color = "light_yellow"
		icon = icons.Cloudsnight
	case "fog":
		icon = icons.Fog
	case "haze":
		icon = icons.Haze
	case "hazenight":
		color = "light_yellow"
		icon = icons.Hazenight
	case "partlycloudyday":
		color = "yellow"
		icon = icons.Partlycloudyday
	case "partlycloudynight":
		color = "light_yellow"
		icon = icons.Partlycloudynight
	case "rain":
		icon = icons.Rain
	case "sleet":
		icon = icons.Sleet
	case "snow":
		color = "white"
		icon = icons.Snow
	case "thunderstorm":
		color = "black"
		icon = icons.Thunderstorm
	case "tornado":
		color = "black"
		icon = icons.Tornado
	case "wind":
		color = "black"
		icon = icons.Wind
	}

	return colorstring.Color("[" + color + "]" + icon), nil
}

func getBearingDetails(degrees float64) string {
	index := int(math.Mod((degrees+11.25)/22.5, 16))
	return Directions[index]
}

func printCommon(weather Weather, unitsFormat UnitMeasures) error {
	if weather.Humidity > 0 {
		humidity := colorstring.Color(fmt.Sprintf("[white]%v%s", weather.Humidity*100, "%"))
		if weather.Humidity > 0.20 {
			fmt.Printf("  Ick! The humidity is %s\n", humidity)
		} else {
			fmt.Printf("  The humidity is %s\n", humidity)
		}
	}

	if weather.PrecipIntensity > 0 {
		precInt := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.PrecipIntensity, unitsFormat.Precipitation))
		fmt.Printf("  The precipitation intensity of %s is %s\n", colorstring.Color("[white]"+weather.PrecipType), precInt)
	}

	if weather.PrecipProbability > 0 {
		prec := colorstring.Color(fmt.Sprintf("[white]%v%s", weather.PrecipProbability*100, "%"))
		fmt.Printf("  The precipitation probability is %s\n", prec)
	}

	if weather.NearestStormDistance > 0 {
		dist := colorstring.Color(fmt.Sprintf("[white]%v %s %v", weather.NearestStormDistance, unitsFormat.Length, getBearingDetails(weather.NearestStormBearing)))
		fmt.Printf("  The nearest storm is %s away\n", dist)
	}

	if weather.WindSpeed > 0 {
		wind := colorstring.Color(fmt.Sprintf("[white]%v %s %v", weather.WindSpeed, unitsFormat.Speed, getBearingDetails(weather.WindBearing)))
		fmt.Printf("  The wind speed is %s\n", wind)
	}

	if weather.CloudCover > 0 {
		cloudCover := colorstring.Color(fmt.Sprintf("[white]%v%s", weather.CloudCover*100, "%"))
		fmt.Printf("  The cloud coverage is %s\n", cloudCover)
	}

	if weather.Visibility < 10 {
		visibility := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.Visibility, unitsFormat.Length))
		fmt.Printf("  The visibility is %s\n", visibility)
	}

	if weather.Pressure > 0 {
		pressure := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.Pressure, "mbar"))
		fmt.Printf("  The pressure is %s\n\n", pressure)
	}

	return nil
}

// PrintCurrent pretty prints the current forecast data.
func PrintCurrent(forecast Forecast, geolocation geocode.Geocode, ignoreAlerts bool, hideIcon bool) error {
	unitsFormat := UnitFormats[forecast.Flags.Units]

	if !hideIcon {
		icon, err := getIcon(forecast.Currently.Icon)
		if err != nil {
			return err
		}

		fmt.Println(icon)
	}

	location := colorstring.Color(fmt.Sprintf("[green]%s in %s", geolocation.City, geolocation.Region))
	fmt.Printf("\nCurrent weather is %s in %s for %s\n", colorstring.Color("[cyan]"+forecast.Currently.Summary), location, colorstring.Color("[cyan]"+epochFormat(forecast.Currently.Time)))

	temp := colorstring.Color(fmt.Sprintf("[magenta]%v%s", forecast.Currently.Temperature, unitsFormat.Degrees))
	feelslike := colorstring.Color(fmt.Sprintf("[magenta]%v%s", forecast.Currently.ApparentTemperature, unitsFormat.Degrees))
	if temp == feelslike {
		fmt.Printf("The temperature is %s\n\n", temp)
	} else {
		fmt.Printf("The temperature is %s, but it feels like %s\n\n", temp, feelslike)
	}

	if !ignoreAlerts {
		for _, alert := range forecast.Alerts {
			if alert.Title != "" {
				fmt.Println(colorstring.Color("[red]" + alert.Title))
			}
			if alert.Description != "" {
				fmt.Print(colorstring.Color("[red]" + alert.Description))
			}
			fmt.Println("\t\t\t" + colorstring.Color("[red]Created: "+epochFormat(alert.Time)))
			fmt.Println("\t\t\t" + colorstring.Color("[red]Expires: "+epochFormat(alert.Expires)) + "\n")
		}
	}

	if err := printCommon(forecast.Currently, unitsFormat); err != nil {
		return err
	}

	if forecast.Hourly.Summary != "" {
		fmt.Printf("%s\n\n", forecast.Hourly.Summary)

		var ticks = []rune(" ▁▂▃▄▅▆▇█")
		rainForecast, showRain := &bytes.Buffer{}, false
		for i := 0; i < 16; i++ {
			p := forecast.Hourly.Data[i].PrecipProbability
			t := int(p*float64(len(ticks)-2)) + 1
			if p == 0 {
				t = 0
			} else {
				showRain = true
			}
			rainForecast.WriteRune(ticks[t])
			rainForecast.WriteRune(ticks[t])
			rainForecast.WriteRune(' ')
		}
		if showRain {
			fmt.Printf("Rain chance: %s\n", rainForecast)
			fmt.Printf("             ")
			for i := 0; i < 4; i++ {
				fmt.Printf("%s         ", epochFormatHour(forecast.Hourly.Data[i*4].Time))
			}
			fmt.Printf("\n\n")
		}
	}

	return nil
}

// PrintDaily pretty prints the daily forecast data.
func PrintDaily(forecast Forecast, days int) error {
	unitsFormat := UnitFormats[forecast.Flags.Units]

	// Ignore the current day as it's printed before
	for index, daily := range forecast.Daily.Data[1:] {
		// only do the amount of days they request
		if index == days {
			break
		}

		fmt.Println(colorstring.Color("[magenta]" + epochFormatDate(daily.Time)))

		tempMax := colorstring.Color(fmt.Sprintf("[blue]%v%s", daily.TemperatureMax, unitsFormat.Degrees))
		tempMin := colorstring.Color(fmt.Sprintf("[blue]%v%s", daily.TemperatureMin, unitsFormat.Degrees))
		feelsLikeMax := colorstring.Color(fmt.Sprintf("[cyan]%v%s", daily.ApparentTemperatureMax, unitsFormat.Degrees))
		feelsLikeMin := colorstring.Color(fmt.Sprintf("[cyan]%v%s", daily.ApparentTemperatureMin, unitsFormat.Degrees))
		fmt.Printf("The temperature high is %s, feels like %s around %s,\n", tempMax, feelsLikeMax, epochFormatTime(daily.TemperatureMaxTime))
		fmt.Printf("and low is %s, feels like %s around %s\n\n", tempMin, feelsLikeMin, epochFormatTime(daily.TemperatureMinTime))

		printCommon(daily, unitsFormat)
	}

	return nil
}
<commit_msg>adjusts humidity and cloud cover output - default width, precision 2 (#41)<commit_after>package forecast

import (
	"bytes"
	"fmt"
	"math"
	"strings"
	"time"

	"github.com/jessfraz/weather/geocode"
	"github.com/jessfraz/weather/icons"
	"github.com/mitchellh/colorstring"
)

// UnitMeasures are the location specific terms for weather data.
type UnitMeasures struct {
	Degrees       string
	Speed         string
	Length        string
	Precipitation string
}

var (
	// UnitFormats describe each regions UnitMeasures.
	UnitFormats = map[string]UnitMeasures{
		"us": {
			Degrees:       "°F",
			Speed:         "mph",
			Length:        "miles",
			Precipitation: "in/hr",
		},
		"si": {
			Degrees:       "°C",
			Speed:         "m/s",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		"ca": {
			Degrees:       "°C",
			Speed:         "km/h",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		// deprecated, use "uk2" in stead
		"uk": {
			Degrees:       "°C",
			Speed:         "mph",
			Length:        "kilometers",
			Precipitation: "mm/h",
		},
		"uk2": {
			Degrees:       "°C",
			Speed:         "mph",
			Length:        "miles",
			Precipitation: "mm/h",
		},
	}
	// Directions contain all the combinations of N,S,E,W
	Directions = []string{
		"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW",
	}
)

func epochFormat(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("January 2 at 3:04pm MST")
}

func epochFormatDate(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("January 2 (Monday)")
}

func epochFormatTime(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	return epochTime.Format("3:04pm MST")
}

func epochFormatHour(seconds int64) string {
	epochTime := time.Unix(0, seconds*int64(time.Second))
	s := epochTime.Format("3pm")
	s = s[:len(s)-1]
	if len(s) == 2 {
		s += " "
	}
	return s
}

func getIcon(iconStr string) (icon string, err error) {
	color := "blue"
	// steralize the icon string name
	iconStr = strings.Replace(strings.Replace(iconStr, "-", "", -1), "_", "", -1)

	switch iconStr {
	case "clear":
		icon = icons.Clear
	case "clearday":
		color = "yellow"
		icon = icons.Clearday
	case "clearnight":
		color = "light_yellow"
		icon = icons.Clearnight
	case "clouds":
		icon = icons.Clouds
	case "cloudy":
		icon = icons.Cloudy
	case "cloudsnight":
		color = "light_yellow"
		icon = icons.Cloudsnight
	case "fog":
		icon = icons.Fog
	case "haze":
		icon = icons.Haze
	case "hazenight":
		color = "light_yellow"
		icon = icons.Hazenight
	case "partlycloudyday":
		color = "yellow"
		icon = icons.Partlycloudyday
	case "partlycloudynight":
		color = "light_yellow"
		icon = icons.Partlycloudynight
	case "rain":
		icon = icons.Rain
	case "sleet":
		icon = icons.Sleet
	case "snow":
		color = "white"
		icon = icons.Snow
	case "thunderstorm":
		color = "black"
		icon = icons.Thunderstorm
	case "tornado":
		color = "black"
		icon = icons.Tornado
	case "wind":
		color = "black"
		icon = icons.Wind
	}

	return colorstring.Color("[" + color + "]" + icon), nil
}

func getBearingDetails(degrees float64) string {
	index := int(math.Mod((degrees+11.25)/22.5, 16))
	return Directions[index]
}

func printCommon(weather Weather, unitsFormat UnitMeasures) error {
	if weather.Humidity > 0 {
		humidity := colorstring.Color(fmt.Sprintf("[white]%.2f%s", weather.Humidity*100, "%"))
		if weather.Humidity > 0.20 {
			fmt.Printf("  Ick! The humidity is %s\n", humidity)
		} else {
			fmt.Printf("  The humidity is %s\n", humidity)
		}
	}

	if weather.PrecipIntensity > 0 {
		precInt := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.PrecipIntensity, unitsFormat.Precipitation))
		fmt.Printf("  The precipitation intensity of %s is %s\n", colorstring.Color("[white]"+weather.PrecipType), precInt)
	}

	if weather.PrecipProbability > 0 {
		prec := colorstring.Color(fmt.Sprintf("[white]%v%s", weather.PrecipProbability*100, "%"))
		fmt.Printf("  The precipitation probability is %s\n", prec)
	}

	if weather.NearestStormDistance > 0 {
		dist := colorstring.Color(fmt.Sprintf("[white]%v %s %v", weather.NearestStormDistance, unitsFormat.Length, getBearingDetails(weather.NearestStormBearing)))
		fmt.Printf("  The nearest storm is %s away\n", dist)
	}

	if weather.WindSpeed > 0 {
		wind := colorstring.Color(fmt.Sprintf("[white]%v %s %v", weather.WindSpeed, unitsFormat.Speed, getBearingDetails(weather.WindBearing)))
		fmt.Printf("  The wind speed is %s\n", wind)
	}

	if weather.CloudCover > 0 {
		cloudCover := colorstring.Color(fmt.Sprintf("[white]%.2f%s", weather.CloudCover*100, "%"))
		fmt.Printf("  The cloud coverage is %s\n", cloudCover)
	}

	if weather.Visibility < 10 {
		visibility := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.Visibility, unitsFormat.Length))
		fmt.Printf("  The visibility is %s\n", visibility)
	}

	if weather.Pressure > 0 {
		pressure := colorstring.Color(fmt.Sprintf("[white]%v %s", weather.Pressure, "mbar"))
		fmt.Printf("  The pressure is %s\n\n", pressure)
	}

	return nil
}

// PrintCurrent pretty prints the current forecast data.
func PrintCurrent(forecast Forecast, geolocation geocode.Geocode, ignoreAlerts bool, hideIcon bool) error {
	unitsFormat := UnitFormats[forecast.Flags.Units]

	if !hideIcon {
		icon, err := getIcon(forecast.Currently.Icon)
		if err != nil {
			return err
		}

		fmt.Println(icon)
	}

	location := colorstring.Color(fmt.Sprintf("[green]%s in %s", geolocation.City, geolocation.Region))
	fmt.Printf("\nCurrent weather is %s in %s for %s\n", colorstring.Color("[cyan]"+forecast.Currently.Summary), location, colorstring.Color("[cyan]"+epochFormat(forecast.Currently.Time)))

	temp := colorstring.Color(fmt.Sprintf("[magenta]%v%s", forecast.Currently.Temperature, unitsFormat.Degrees))
	feelslike := colorstring.Color(fmt.Sprintf("[magenta]%v%s", forecast.Currently.ApparentTemperature, unitsFormat.Degrees))
	if temp == feelslike {
		fmt.Printf("The temperature is %s\n\n", temp)
	} else {
		fmt.Printf("The temperature is %s, but it feels like %s\n\n", temp, feelslike)
	}

	if !ignoreAlerts {
		for _, alert := range forecast.Alerts {
			if alert.Title != "" {
				fmt.Println(colorstring.Color("[red]" + alert.Title))
			}
			if alert.Description != "" {
				fmt.Print(colorstring.Color("[red]" + alert.Description))
			}
			fmt.Println("\t\t\t" + colorstring.Color("[red]Created: "+epochFormat(alert.Time)))
			fmt.Println("\t\t\t" + colorstring.Color("[red]Expires: "+epochFormat(alert.Expires)) + "\n")
		}
	}

	if err := printCommon(forecast.Currently, unitsFormat); err != nil {
		return err
	}

	if forecast.Hourly.Summary != "" {
		fmt.Printf("%s\n\n", forecast.Hourly.Summary)

		var ticks = []rune(" ▁▂▃▄▅▆▇█")
		rainForecast, showRain := &bytes.Buffer{}, false
		for i := 0; i < 16; i++ {
			p := forecast.Hourly.Data[i].PrecipProbability
			t := int(p*float64(len(ticks)-2)) + 1
			if p == 0 {
				t = 0
			} else {
				showRain = true
			}
			rainForecast.WriteRune(ticks[t])
			rainForecast.WriteRune(ticks[t])
			rainForecast.WriteRune(' ')
		}
		if showRain {
			fmt.Printf("Rain chance: %s\n", rainForecast)
			fmt.Printf("             ")
			for i := 0; i < 4; i++ {
				fmt.Printf("%s         ", epochFormatHour(forecast.Hourly.Data[i*4].Time))
			}
			fmt.Printf("\n\n")
		}
	}

	return nil
}

// PrintDaily pretty prints the daily forecast data.
func PrintDaily(forecast Forecast, days int) error {
	unitsFormat := UnitFormats[forecast.Flags.Units]

	// Ignore the current day as it's printed before
	for index, daily := range forecast.Daily.Data[1:] {
		// only do the amount of days they request
		if index == days {
			break
		}

		fmt.Println(colorstring.Color("[magenta]" + epochFormatDate(daily.Time)))

		tempMax := colorstring.Color(fmt.Sprintf("[blue]%v%s", daily.TemperatureMax, unitsFormat.Degrees))
		tempMin := colorstring.Color(fmt.Sprintf("[blue]%v%s", daily.TemperatureMin, unitsFormat.Degrees))
		feelsLikeMax := colorstring.Color(fmt.Sprintf("[cyan]%v%s", daily.ApparentTemperatureMax, unitsFormat.Degrees))
		feelsLikeMin := colorstring.Color(fmt.Sprintf("[cyan]%v%s", daily.ApparentTemperatureMin, unitsFormat.Degrees))
		fmt.Printf("The temperature high is %s, feels like %s around %s,\n", tempMax, feelsLikeMax, epochFormatTime(daily.TemperatureMaxTime))
		fmt.Printf("and low is %s, feels like %s around %s\n\n", tempMin, feelsLikeMin, epochFormatTime(daily.TemperatureMinTime))

		printCommon(daily, unitsFormat)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/router"
	"github.com/olekukonko/tablewriter"
)

var UsersCmd = cli.Command{
	Name:  "users",
	Usage: "manage abalone users",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			ShortName: "c",
			Usage:     "creates a user",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Value: "",
				},
				cli.StringFlag{
					Name:  "email, e",
					Value: "",
				},
			},
			Action: func(c *cli.Context) {
				if err := CreateUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "list",
			ShortName: "l",
			Usage:     "lists users",
			Action: func(c *cli.Context) {
				if err := ListUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "delete",
			ShortName: "d",
			Usage:     "delete user by id",
			Action: func(c *cli.Context) {
				if err := DeleteUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
	},
}

func CreateUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersCreate).URL()
	if err != nil {
		return err
	}

	if !c.IsSet("name") {
		return errors.New("name is required")
	}
	n := c.String("name")

	if !c.IsSet("email") {
		return errors.New("email is required")
	}
	e := c.String("email")

	req := api.User{
		Name:  n,
		Email: e,
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(&req); err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Post(url, "application/json", &buf)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}

func ListUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.Users).URL()
	if err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	var users []api.User
	if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
		return fmt.Errorf("error decoding json response: %s", err)
	}

	table := tablewriter.NewWriter(c.App.Writer)
	table.SetHeader([]string{"ID", "Name", "Email", "Created", "Updated"})
	for _, u := range users {
		row := []string{
			strconv.FormatInt(u.ID, 10),
			u.Name,
			u.Email,
			u.CreatedAt.Format("Mon Jan 2 15:04:05"),
			u.UpdatedAt.Format("Mon Jan 2 15:04:05"),
		}
		table.Append(row)
	}
	table.Render() // Send output
	return nil
}

func DeleteUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersDelete).URL("id", c.Args().First())
	if err != nil {
		return fmt.Errorf("error parsing user id: %s", err)
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}
<commit_msg>feat(ctl) add "users" ShortName "u"<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/router"
	"github.com/olekukonko/tablewriter"
)

var UsersCmd = cli.Command{
	Name:      "users",
	ShortName: "u",
	Usage:     "manage abalone users",
	Subcommands: []cli.Command{
		{
			Name:      "create",
			ShortName: "c",
			Usage:     "creates a user",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Value: "",
				},
				cli.StringFlag{
					Name:  "email, e",
					Value: "",
				},
			},
			Action: func(c *cli.Context) {
				if err := CreateUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "list",
			ShortName: "l",
			Usage:     "lists users",
			Action: func(c *cli.Context) {
				if err := ListUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
		{
			Name:      "delete",
			ShortName: "d",
			Usage:     "delete user by id",
			Action: func(c *cli.Context) {
				if err := DeleteUsersHandler(c); err != nil {
					log.Fatal(err)
				}
			},
		},
	},
}

func CreateUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersCreate).URL()
	if err != nil {
		return err
	}

	if !c.IsSet("name") {
		return errors.New("name is required")
	}
	n := c.String("name")

	if !c.IsSet("email") {
		return errors.New("email is required")
	}
	e := c.String("email")

	req := api.User{
		Name:  n,
		Email: e,
	}
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(&req); err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Post(url, "application/json", &buf)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}

func ListUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.Users).URL()
	if err != nil {
		return err
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	var users []api.User
	if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
		return fmt.Errorf("error decoding json response: %s", err)
	}

	table := tablewriter.NewWriter(c.App.Writer)
	table.SetHeader([]string{"ID", "Name", "Email", "Created", "Updated"})
	for _, u := range users {
		row := []string{
			strconv.FormatInt(u.ID, 10),
			u.Name,
			u.Email,
			u.CreatedAt.Format("Mon Jan 2 15:04:05"),
			u.UpdatedAt.Format("Mon Jan 2 15:04:05"),
		}
		table.Append(row)
	}
	table.Render() // Send output
	return nil
}

func DeleteUsersHandler(c *cli.Context) error {
	r := router.NewAPIRouter()
	path, err := r.Get(router.UsersDelete).URL("id", c.Args().First())
	if err != nil {
		return fmt.Errorf("error parsing user id: %s", err)
	}
	url := fmt.Sprintf("http://%s%s", c.GlobalString("httpd"), path.String())
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("error: %s", resp.Status)
	}
	return nil
}
<|endoftext|>