<commit_before>package apk

import (
	"github.com/shogo82148/androidbinary"
)

// Instrumentation is an application instrumentation code.
type Instrumentation struct {
	Name            androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Target          androidbinary.String `xml:"http://schemas.android.com/apk/res/android targetPackage,attr"`
	HandleProfiling androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android handleProfiling,attr"`
	FunctionalTest  androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android functionalTest,attr"`
}

// ActivityAction is an action of an activity.
type ActivityAction struct {
	Name androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}

// ActivityCategory is a category of an activity.
type ActivityCategory struct {
	Name androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}

// ActivityIntentFilter is an androidbinary.Int32ent filter of an activity.
type ActivityIntentFilter struct {
	Actions    []ActivityAction   `xml:"action"`
	Categories []ActivityCategory `xml:"category"`
}

// AppActivity is an activity in an application.
type AppActivity struct {
	Theme         androidbinary.String   `xml:"http://schemas.android.com/apk/res/android theme,attr"`
	Name          androidbinary.String   `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Label         androidbinary.String   `xml:"http://schemas.android.com/apk/res/android label,attr"`
	IntentFilters []ActivityIntentFilter `xml:"intent-filter"`
}

// AppActivityAlias https://developer.android.com/guide/topics/manifest/activity-alias-element
type AppActivityAlias struct {
	Name           androidbinary.String   `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Label          androidbinary.String   `xml:"http://schemas.android.com/apk/res/android label,attr"`
	TargetActivity androidbinary.String   `xml:"http://schemas.android.com/apk/res/android targetActivity,attr"`
	IntentFilters  []ActivityIntentFilter `xml:"intent-filter"`
}

// MetaData is a metadata in an application.
type MetaData struct {
	Name  androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Value androidbinary.String `xml:"http://schemas.android.com/apk/res/android value,attr"`
}

// Application is an application in an APK.
type Application struct {
	AllowTaskReparenting  androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android allowTaskReparenting,attr"`
	AllowBackup           androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android allowBackup,attr"`
	BackupAgent           androidbinary.String `xml:"http://schemas.android.com/apk/res/android backupAgent,attr"`
	Debuggable            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android debuggable,attr"`
	Description           androidbinary.String `xml:"http://schemas.android.com/apk/res/android description,attr"`
	Enabled               androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android enabled,attr"`
	HasCode               androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android hasCode,attr"`
	HardwareAccelerated   androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android hardwareAccelerated,attr"`
	Icon                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android icon,attr"`
	KillAfterRestore      androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android killAfterRestore,attr"`
	LargeHeap             androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android largeHeap,attr"`
	Label                 androidbinary.String `xml:"http://schemas.android.com/apk/res/android label,attr"`
	Logo                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android logo,attr"`
	ManageSpaceActivity   androidbinary.String `xml:"http://schemas.android.com/apk/res/android manageSpaceActivity,attr"`
	Name                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Permission            androidbinary.String `xml:"http://schemas.android.com/apk/res/android permission,attr"`
	Persistent            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android persistent,attr"`
	Process               androidbinary.String `xml:"http://schemas.android.com/apk/res/android process,attr"`
	RestoreAnyVersion     androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android restoreAnyVersion,attr"`
	RequiredAccountType   androidbinary.String `xml:"http://schemas.android.com/apk/res/android requiredAccountType,attr"`
	RestrictedAccountType androidbinary.String `xml:"http://schemas.android.com/apk/res/android restrictedAccountType,attr"`
	SupportsRtl           androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android supportsRtl,attr"`
	TaskAffinity          androidbinary.String `xml:"http://schemas.android.com/apk/res/android taskAffinity,attr"`
	TestOnly              androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android testOnly,attr"`
	Theme                 androidbinary.String `xml:"http://schemas.android.com/apk/res/android theme,attr"`
	UIOptions             androidbinary.String `xml:"http://schemas.android.com/apk/res/android uiOptions,attr"`
	VMSafeMode            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android vmSafeMode,attr"`
	Activities            []AppActivity        `xml:"activity"`
	ActivityAliases       []AppActivityAlias   `xml:"activity-alias"`
	MetaData              []MetaData           `xml:"meta-data"`
}

// UsesSDK is target SDK version.
type UsesSDK struct {
	Min    androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android minSdkVersion,attr"`
	Target androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android targetSdkVersion,attr"`
	Max    androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android maxSdkVersion,attr"`
}

// Manifest is a manifest of an APK.
type Manifest struct {
	Package     androidbinary.String `xml:"package,attr"`
	VersionCode androidbinary.Int32  `xml:"http://schemas.android.com/apk/res/android versionCode,attr"`
	VersionName androidbinary.String `xml:"http://schemas.android.com/apk/res/android versionName,attr"`
	App         Application          `xml:"application"`
	Instrument  Instrumentation      `xml:"instrumentation"`
	SDK         UsesSDK              `xml:"uses-sdk"`
}
<commit_msg>add ScreenOrientation for AppActivity<commit_after>package apk

import (
	"github.com/shogo82148/androidbinary"
)

// Instrumentation is an application instrumentation code.
type Instrumentation struct {
	Name            androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Target          androidbinary.String `xml:"http://schemas.android.com/apk/res/android targetPackage,attr"`
	HandleProfiling androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android handleProfiling,attr"`
	FunctionalTest  androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android functionalTest,attr"`
}

// ActivityAction is an action of an activity.
type ActivityAction struct {
	Name androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}

// ActivityCategory is a category of an activity.
type ActivityCategory struct {
	Name androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}

// ActivityIntentFilter is an androidbinary.Int32ent filter of an activity.
type ActivityIntentFilter struct {
	Actions    []ActivityAction   `xml:"action"`
	Categories []ActivityCategory `xml:"category"`
}

// AppActivity is an activity in an application.
type AppActivity struct {
	Theme             androidbinary.String   `xml:"http://schemas.android.com/apk/res/android theme,attr"`
	Name              androidbinary.String   `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Label             androidbinary.String   `xml:"http://schemas.android.com/apk/res/android label,attr"`
	ScreenOrientation androidbinary.String   `xml:"http://schemas.android.com/apk/res/android screenOrientation,attr"`
	IntentFilters     []ActivityIntentFilter `xml:"intent-filter"`
}

// AppActivityAlias https://developer.android.com/guide/topics/manifest/activity-alias-element
type AppActivityAlias struct {
	Name           androidbinary.String   `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Label          androidbinary.String   `xml:"http://schemas.android.com/apk/res/android label,attr"`
	TargetActivity androidbinary.String   `xml:"http://schemas.android.com/apk/res/android targetActivity,attr"`
	IntentFilters  []ActivityIntentFilter `xml:"intent-filter"`
}

// MetaData is a metadata in an application.
type MetaData struct {
	Name  androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Value androidbinary.String `xml:"http://schemas.android.com/apk/res/android value,attr"`
}

// Application is an application in an APK.
type Application struct {
	AllowTaskReparenting  androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android allowTaskReparenting,attr"`
	AllowBackup           androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android allowBackup,attr"`
	BackupAgent           androidbinary.String `xml:"http://schemas.android.com/apk/res/android backupAgent,attr"`
	Debuggable            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android debuggable,attr"`
	Description           androidbinary.String `xml:"http://schemas.android.com/apk/res/android description,attr"`
	Enabled               androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android enabled,attr"`
	HasCode               androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android hasCode,attr"`
	HardwareAccelerated   androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android hardwareAccelerated,attr"`
	Icon                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android icon,attr"`
	KillAfterRestore      androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android killAfterRestore,attr"`
	LargeHeap             androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android largeHeap,attr"`
	Label                 androidbinary.String `xml:"http://schemas.android.com/apk/res/android label,attr"`
	Logo                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android logo,attr"`
	ManageSpaceActivity   androidbinary.String `xml:"http://schemas.android.com/apk/res/android manageSpaceActivity,attr"`
	Name                  androidbinary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
	Permission            androidbinary.String `xml:"http://schemas.android.com/apk/res/android permission,attr"`
	Persistent            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android persistent,attr"`
	Process               androidbinary.String `xml:"http://schemas.android.com/apk/res/android process,attr"`
	RestoreAnyVersion     androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android restoreAnyVersion,attr"`
	RequiredAccountType   androidbinary.String `xml:"http://schemas.android.com/apk/res/android requiredAccountType,attr"`
	RestrictedAccountType androidbinary.String `xml:"http://schemas.android.com/apk/res/android restrictedAccountType,attr"`
	SupportsRtl           androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android supportsRtl,attr"`
	TaskAffinity          androidbinary.String `xml:"http://schemas.android.com/apk/res/android taskAffinity,attr"`
	TestOnly              androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android testOnly,attr"`
	Theme                 androidbinary.String `xml:"http://schemas.android.com/apk/res/android theme,attr"`
	UIOptions             androidbinary.String `xml:"http://schemas.android.com/apk/res/android uiOptions,attr"`
	VMSafeMode            androidbinary.Bool   `xml:"http://schemas.android.com/apk/res/android vmSafeMode,attr"`
	Activities            []AppActivity        `xml:"activity"`
	ActivityAliases       []AppActivityAlias   `xml:"activity-alias"`
	MetaData              []MetaData           `xml:"meta-data"`
}

// UsesSDK is target SDK version.
type UsesSDK struct {
	Min    androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android minSdkVersion,attr"`
	Target androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android targetSdkVersion,attr"`
	Max    androidbinary.Int32 `xml:"http://schemas.android.com/apk/res/android maxSdkVersion,attr"`
}

// Manifest is a manifest of an APK.
type Manifest struct {
	Package     androidbinary.String `xml:"package,attr"`
	VersionCode androidbinary.Int32  `xml:"http://schemas.android.com/apk/res/android versionCode,attr"`
	VersionName androidbinary.String `xml:"http://schemas.android.com/apk/res/android versionName,attr"`
	App         Application          `xml:"application"`
	Instrument  Instrumentation      `xml:"instrumentation"`
	SDK         UsesSDK              `xml:"uses-sdk"`
}
<|endoftext|>


<commit_before>package influxdb_v2

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"net/url"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/config"
	"github.com/influxdata/telegraf/plugins/common/tls"
	"github.com/influxdata/telegraf/plugins/outputs"
	"github.com/influxdata/telegraf/plugins/serializers/influx"
)

var (
	defaultURL = "http://localhost:8086"

	ErrMissingURL = errors.New("missing URL")
)

type Client interface {
	Write(context.Context, []telegraf.Metric) error

	URL() string // for logging
	Close()
}

type InfluxDB struct {
	URLs             []string          `toml:"urls"`
	Token            string            `toml:"token"`
	Organization     string            `toml:"organization"`
	Bucket           string            `toml:"bucket"`
	BucketTag        string            `toml:"bucket_tag"`
	ExcludeBucketTag bool              `toml:"exclude_bucket_tag"`
	Timeout          config.Duration   `toml:"timeout"`
	HTTPHeaders      map[string]string `toml:"http_headers"`
	HTTPProxy        string            `toml:"http_proxy"`
	UserAgent        string            `toml:"user_agent"`
	ContentEncoding  string            `toml:"content_encoding"`
	UintSupport      bool              `toml:"influx_uint_support"`
	tls.ClientConfig

	Log telegraf.Logger `toml:"-"`

	clients []Client
}

func (i *InfluxDB) Connect() error {
	if len(i.URLs) == 0 {
		i.URLs = append(i.URLs, defaultURL)
	}

	for _, u := range i.URLs {
		parts, err := url.Parse(u)
		if err != nil {
			return fmt.Errorf("error parsing url [%q]: %v", u, err)
		}

		var proxy *url.URL
		if len(i.HTTPProxy) > 0 {
			proxy, err = url.Parse(i.HTTPProxy)
			if err != nil {
				return fmt.Errorf("error parsing proxy_url [%s]: %v", i.HTTPProxy, err)
			}
		}

		switch parts.Scheme {
		case "http", "https", "unix":
			c, err := i.getHTTPClient(parts, proxy)
			if err != nil {
				return err
			}

			i.clients = append(i.clients, c)
		default:
			return fmt.Errorf("unsupported scheme [%q]: %q", u, parts.Scheme)
		}
	}

	return nil
}

func (i *InfluxDB) Close() error {
	for _, client := range i.clients {
		client.Close()
	}
	return nil
}

// Write sends metrics to one of the configured servers, logging each
// unsuccessful. If all servers fail, return an error.
func (i *InfluxDB) Write(metrics []telegraf.Metric) error {
	ctx := context.Background()

	var err error
	p := rand.Perm(len(i.clients))
	for _, n := range p {
		client := i.clients[n]
		err = client.Write(ctx, metrics)
		if err == nil {
			return nil
		}

		i.Log.Errorf("When writing to [%s]: %v", client.URL(), err)
	}

	return err
}

func (i *InfluxDB) getHTTPClient(address *url.URL, proxy *url.URL) (Client, error) {
	tlsConfig, err := i.ClientConfig.TLSConfig()
	if err != nil {
		return nil, err
	}

	httpConfig := &HTTPConfig{
		URL:              address,
		Token:            i.Token,
		Organization:     i.Organization,
		Bucket:           i.Bucket,
		BucketTag:        i.BucketTag,
		ExcludeBucketTag: i.ExcludeBucketTag,
		Timeout:          time.Duration(i.Timeout),
		Headers:          i.HTTPHeaders,
		Proxy:            proxy,
		UserAgent:        i.UserAgent,
		ContentEncoding:  i.ContentEncoding,
		TLSConfig:        tlsConfig,
		Serializer:       i.newSerializer(),
		Log:              i.Log,
	}

	c, err := NewHTTPClient(httpConfig)
	if err != nil {
		return nil, fmt.Errorf("error creating HTTP client [%s]: %v", address, err)
	}

	return c, nil
}

func (i *InfluxDB) newSerializer() *influx.Serializer {
	serializer := influx.NewSerializer()
	if i.UintSupport {
		serializer.SetFieldTypeSupport(influx.UintSupport)
	}

	return serializer
}

func init() {
	outputs.Add("influxdb_v2", func() telegraf.Output {
		return &InfluxDB{
			Timeout:         config.Duration(time.Second * 5),
			ContentEncoding: "gzip",
		}
	})
}
<commit_msg>fix: update influxdb_v2 error message (#10958)<commit_after>package influxdb_v2

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"net/url"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/config"
	"github.com/influxdata/telegraf/plugins/common/tls"
	"github.com/influxdata/telegraf/plugins/outputs"
	"github.com/influxdata/telegraf/plugins/serializers/influx"
)

var (
	defaultURL = "http://localhost:8086"

	ErrMissingURL = errors.New("missing URL")
)

type Client interface {
	Write(context.Context, []telegraf.Metric) error

	URL() string // for logging
	Close()
}

type InfluxDB struct {
	URLs             []string          `toml:"urls"`
	Token            string            `toml:"token"`
	Organization     string            `toml:"organization"`
	Bucket           string            `toml:"bucket"`
	BucketTag        string            `toml:"bucket_tag"`
	ExcludeBucketTag bool              `toml:"exclude_bucket_tag"`
	Timeout          config.Duration   `toml:"timeout"`
	HTTPHeaders      map[string]string `toml:"http_headers"`
	HTTPProxy        string            `toml:"http_proxy"`
	UserAgent        string            `toml:"user_agent"`
	ContentEncoding  string            `toml:"content_encoding"`
	UintSupport      bool              `toml:"influx_uint_support"`
	tls.ClientConfig

	Log telegraf.Logger `toml:"-"`

	clients []Client
}

func (i *InfluxDB) Connect() error {
	if len(i.URLs) == 0 {
		i.URLs = append(i.URLs, defaultURL)
	}

	for _, u := range i.URLs {
		parts, err := url.Parse(u)
		if err != nil {
			return fmt.Errorf("error parsing url [%q]: %v", u, err)
		}

		var proxy *url.URL
		if len(i.HTTPProxy) > 0 {
			proxy, err = url.Parse(i.HTTPProxy)
			if err != nil {
				return fmt.Errorf("error parsing proxy_url [%s]: %v", i.HTTPProxy, err)
			}
		}

		switch parts.Scheme {
		case "http", "https", "unix":
			c, err := i.getHTTPClient(parts, proxy)
			if err != nil {
				return err
			}

			i.clients = append(i.clients, c)
		default:
			return fmt.Errorf("unsupported scheme [%q]: %q", u, parts.Scheme)
		}
	}

	return nil
}

func (i *InfluxDB) Close() error {
	for _, client := range i.clients {
		client.Close()
	}
	return nil
}

// Write sends metrics to one of the configured servers, logging each
// unsuccessful. If all servers fail, return an error.
func (i *InfluxDB) Write(metrics []telegraf.Metric) error {
	ctx := context.Background()

	var err error
	p := rand.Perm(len(i.clients))
	for _, n := range p {
		client := i.clients[n]
		err = client.Write(ctx, metrics)
		if err == nil {
			return nil
		}

		i.Log.Errorf("When writing to [%s]: %v", client.URL(), err)
	}

	return fmt.Errorf("failed to send metrics to any configured server(s)")
}

func (i *InfluxDB) getHTTPClient(address *url.URL, proxy *url.URL) (Client, error) {
	tlsConfig, err := i.ClientConfig.TLSConfig()
	if err != nil {
		return nil, err
	}

	httpConfig := &HTTPConfig{
		URL:              address,
		Token:            i.Token,
		Organization:     i.Organization,
		Bucket:           i.Bucket,
		BucketTag:        i.BucketTag,
		ExcludeBucketTag: i.ExcludeBucketTag,
		Timeout:          time.Duration(i.Timeout),
		Headers:          i.HTTPHeaders,
		Proxy:            proxy,
		UserAgent:        i.UserAgent,
		ContentEncoding:  i.ContentEncoding,
		TLSConfig:        tlsConfig,
		Serializer:       i.newSerializer(),
		Log:              i.Log,
	}

	c, err := NewHTTPClient(httpConfig)
	if err != nil {
		return nil, fmt.Errorf("error creating HTTP client [%s]: %v", address, err)
	}

	return c, nil
}

func (i *InfluxDB) newSerializer() *influx.Serializer {
	serializer := influx.NewSerializer()
	if i.UintSupport {
		serializer.SetFieldTypeSupport(influx.UintSupport)
	}

	return serializer
}

func init() {
	outputs.Add("influxdb_v2", func() telegraf.Output {
		return &InfluxDB{
			Timeout:         config.Duration(time.Second * 5),
			ContentEncoding: "gzip",
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/andres-erbsen/chatterbox/client"
	"github.com/andres-erbsen/chatterbox/proto"
	"github.com/andres-erbsen/chatterbox/transport"
	//	"github.com/andres-erbsen/client/clientutil"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
)

type hex32Byte [32]byte

func (h *hex32Byte) String() string {
	return hex.EncodeToString(h[:])
}
func (h *hex32Byte) Set(value string) error {
	if len(value) != 2*32 {
		return fmt.Errorf("Server pubkey must be 64 hex digits long, got %d", len(value))
	}
	_, err := hex.Decode(h[:], []byte(value))
	if err != nil {
		return err
	}
	return err
}

func main() {
	dename := flag.String("dename", "", "Your dename username.")
	var serverTransportPubkey [32]byte
	flag.Var((*hex32Byte)(&serverTransportPubkey), "server-pubkey", "The TCP port which the server listens on. Note that people sending you mesages expct to be able to reach your home server at port 1984.")
	serverAddress := flag.String("server-host", "", "The IP address or hostname on which your (prospective) home server server can be reached")
	serverPort := flag.Int("server-port", 1984, "The TCP port which the server listens on.")
	dir := flag.String("account-directory", "", "Dedicated directory for the account.")
	flag.Parse()

	if *dename == "" || serverTransportPubkey == [32]byte{} || *serverAddress == "" {
		flag.Usage()
		os.Exit(2)
	}
	if *dir == "" {
		*dir = filepath.Join(os.Getenv("HOME"), ".chatterbox", *dename)
	}

	secretConfig := &proto.LocalAccountConfig{
		ServerAddressTCP:  *serverAddress,
		ServerPortTCP:     int32(*serverPort),
		ServerTransportPK: serverTransportPubkey,
		Dename:            []byte(*dename),
	}
	publicProfile := &proto.Profile{
		ServerAddressTCP:  *serverAddress,
		ServerPortTCP:     int32(*serverPort),
		ServerTransportPK: serverTransportPubkey,
	}
	if err := client.GenerateLongTermKeys(secretConfig, publicProfile, rand.Reader); err != nil {
		panic(err)
	}
	secretConfigBytes, err := secretConfig.Marshal()
	if err != nil {
		panic(err)
	}
	publicProfileBytes, err := publicProfile.Marshal()
	if err != nil {
		panic(err)
	}

	if err := os.Mkdir(*dir, 0700); err != nil && !os.IsExist(err) {
		fmt.Fprintf(os.Stderr, "could not create directory %s: %s", *dir, err)
		os.Exit(2)
	}
	configFilePath := filepath.Join(*dir, "config.pb")
	if _, err := os.Stat(configFilePath); !os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "file already exists: %s\n", configFilePath)
		os.Exit(2)
	}
	if err := ioutil.WriteFile(configFilePath, secretConfigBytes, 0600); err != nil {
		// TODO: "WriteFileSync" -- issue fsync after write
		fmt.Fprintf(os.Stderr, "error writing file %s: %s\n", configFilePath, err)
		os.Exit(2)
	}
	profileFilePath := filepath.Join(*dir, "profile.pb")
	if err := ioutil.WriteFile(profileFilePath, publicProfileBytes, 0600); err != nil {
		// TODO: "WriteFileSync" -- issue fsync after write
		fmt.Fprintf(os.Stderr, "error writing file %s: %s\n", profileFilePath, err)
		os.Exit(2)
	}

	fmt.Printf("You may use the following command to link this account with your dename profile:.\n"+
		"dnmgr set '%s' 1984 - < %s\n", *dename, profileFilePath)

	// TODO: use TOR
	fmt.Printf("Registering with the server...\n")
	plainConn, err := net.Dial("tcp", net.JoinHostPort(*serverAddress, fmt.Sprint(*serverPort)))
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to server at %s%s: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	conn, _, err := transport.Handshake(plainConn,
		(*[32]byte)(&publicProfile.UserIDAtServer),
		(*[32]byte)(&secretConfig.TransportSecretKeyForServer),
		&serverTransportPubkey, client.MAX_MESSAGE_SIZE)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to server at %s%s: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	if err := client.CreateAccount(conn, make([]byte, client.MAX_MESSAGE_SIZE),
		make([]byte, client.MAX_MESSAGE_SIZE)); err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to serverat %s:%d: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	fmt.Printf("Account initialization done.\n")
}
<commit_msg>Fixed bug in chatterbox-init<commit_after>package main

import (
	"flag"
	"github.com/andres-erbsen/chatterbox/client"
	"github.com/andres-erbsen/chatterbox/proto"
	"github.com/andres-erbsen/chatterbox/transport"
	//	"github.com/andres-erbsen/client/clientutil"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
)

type hex32Byte [32]byte

func (h *hex32Byte) String() string {
	return hex.EncodeToString(h[:])
}
func (h *hex32Byte) Set(value string) error {
	if len(value) != 2*32 {
		return fmt.Errorf("Server pubkey must be 64 hex digits long, got %d", len(value))
	}
	_, err := hex.Decode(h[:], []byte(value))
	if err != nil {
		return err
	}
	return err
}

func main() {
	dename := flag.String("dename", "", "Your dename username.")
	var serverTransportPubkey [32]byte
	flag.Var((*hex32Byte)(&serverTransportPubkey), "server-pubkey", "The TCP port which the server listens on. Note that people sending you mesages expct to be able to reach your home server at port 1984.")
	serverAddress := flag.String("server-host", "", "The IP address or hostname on which your (prospective) home server server can be reached")
	serverPort := flag.Int("server-port", 1984, "The TCP port which the server listens on.")
	dir := flag.String("account-directory", "", "Dedicated directory for the account.")
	flag.Parse()

	if *dename == "" || serverTransportPubkey == [32]byte{} || *serverAddress == "" {
		flag.Usage()
		os.Exit(2)
	}
	if *dir == "" {
		*dir = filepath.Join(os.Getenv("HOME"), ".chatterbox", *dename)
	}

	secretConfig := &proto.LocalAccountConfig{
		ServerAddressTCP:  *serverAddress,
		ServerPortTCP:     int32(*serverPort),
		ServerTransportPK: serverTransportPubkey,
		Dename:            []byte(*dename),
	}
	publicProfile := &proto.Profile{
		ServerAddressTCP:  *serverAddress,
		ServerPortTCP:     int32(*serverPort),
		ServerTransportPK: serverTransportPubkey,
	}
	if err := client.GenerateLongTermKeys(secretConfig, publicProfile, rand.Reader); err != nil {
		panic(err)
	}
	secretConfigBytes, err := secretConfig.Marshal()
	if err != nil {
		panic(err)
	}
	publicProfileBytes, err := publicProfile.Marshal()
	if err != nil {
		panic(err)
	}

	if err := os.Mkdir(*dir, 0700); err != nil && !os.IsExist(err) {
		fmt.Fprintf(os.Stderr, "could not create directory %s: %s", *dir, err)
		os.Exit(2)
	}
	configFilePath := filepath.Join(*dir, "config.pb")
	if _, err := os.Stat(configFilePath); !os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "file already exists: %s\n", configFilePath)
		os.Exit(2)
	}
	if err := ioutil.WriteFile(configFilePath, secretConfigBytes, 0600); err != nil {
		// TODO: "WriteFileSync" -- issue fsync after write
		fmt.Fprintf(os.Stderr, "error writing file %s: %s\n", configFilePath, err)
		os.Exit(2)
	}
	profileFilePath := filepath.Join(*dir, "profile.pb")
	if err := ioutil.WriteFile(profileFilePath, publicProfileBytes, 0600); err != nil {
		// TODO: "WriteFileSync" -- issue fsync after write
		fmt.Fprintf(os.Stderr, "error writing file %s: %s\n", profileFilePath, err)
		os.Exit(2)
	}

	fmt.Printf("You may use the following command to link this account with your dename profile:.\n"+
		"dnmgr set '%s' 1984 - < %s\n", *dename, profileFilePath)

	// TODO: use TOR
	fmt.Printf("Registering with the server...\n")
	plainConn, err := net.Dial("tcp", net.JoinHostPort(*serverAddress, fmt.Sprint(*serverPort)))
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to server at %s%s: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	conn, _, err := transport.Handshake(plainConn,
		(*[32]byte)(&publicProfile.UserIDAtServer),
		(*[32]byte)(&secretConfig.TransportSecretKeyForServer),
		&serverTransportPubkey, proto.SERVER_MESSAGE_SIZE)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to server at %s%s: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	if err := client.CreateAccount(conn, make([]byte, proto.SERVER_MESSAGE_SIZE),
		make([]byte, proto.SERVER_MESSAGE_SIZE)); err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to serverat %s:%d: %s\n",
			*serverAddress, *serverPort, err)
		os.Exit(1)
	}
	fmt.Printf("Account initialization done.\n")
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"github.com/callumj/weave/core"
	"github.com/callumj/weave/remote"
	"github.com/callumj/weave/tools"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

func performExtraction(args []string) {
	if len(args) < 3 {
		panicQuitf("Usage: %v ENCRYPTED_FILE KEY_FILE [OUT_DIRECTORY]\r\n", args[0])
	}

	target := args[1]
	keyfile := args[2]

	var eTag string

	matched, _ := regexp.MatchString("^https?:\\/\\/", target)
	if matched {
		if len(args) == 3 {
			panicQuitf("A OUT_DIRECTORY must be specified if using HTTP\r\n")
		} else {
			resp := remote.DownloadRemoteFile(target, args[3])
			if resp == nil {
				panicQuit()
			} else {
				target = resp.FilePath
				eTag = resp.ETag
			}
		}
	}

	var out string

	var success bool
	if len(args) >= 4 {
		out = strings.Join([]string{args[3], "tmp"}, ".")
		success = core.DecryptFile(target, out, keyfile)
	} else {
		out = strings.Replace(target, ".enc", "", 1)
		out = strings.Join([]string{out, "tmp"}, ".")
		if out == target {
			panicQuitf("Cannot determine the out file, please specify")
		}
		success = core.DecryptFile(target, out, keyfile)
	}

	var ensureDirectory = regexp.MustCompile(`(\.(tmp|tgz|tar|gz))+`)
	directory := ensureDirectory.ReplaceAllString(out, "")

	directory, _ = filepath.Abs(directory)

	if !tools.PathExists(directory) {
		os.Mkdir(directory, 0770)
	}

	if success {
		success = core.ExtractArchive(out, directory)
	}

	tools.CleanUpIfNeeded(out)

	if success && len(eTag) != 0 {
		etagfile := fmt.Sprintf("%v/.weave.etag", directory)
		ioutil.WriteFile(etagfile, []byte(eTag), 0775)
	}

	if success {
		runPostExtractionCallback(directory)
	}

	if !success {
		panicQuit()
	}
}

func runPostExtractionCallback(directory string) {
	postExtractionPath := fmt.Sprintf("%v/post_extraction.sh", directory)
	if tools.PathExists(postExtractionPath) {
		bashLoc, _ := exec.LookPath("bash")
		if len(bashLoc) == 0 {
			bashLoc = "/bin/bash"
		}
		cmd := exec.Command(bashLoc, postExtractionPath)
		cmd.Dir = directory
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			panicQuitf("Unable to open STDOUT")
		}
		if err := cmd.Start(); err != nil {
			panicQuitf("Unable to start %v (%v)\r\n", postExtractionPath, err)
		}

		logPath := fmt.Sprintf("%v/post_extraction.log", directory)
		stdoutLogFile, err := os.Create(logPath)
		if err != nil {
			panicQuitf("Unable to open file for logging %v\r\n", logPath)
		}
		defer stdoutLogFile.Close()

		_, err = io.Copy(stdoutLogFile, stdout)
		if err != nil {
			panicQuitf("Failed to copy STDOUT to file\r\n")
		}

		if err := cmd.Wait(); err != nil {
			panicQuitf("Failed finalise command (%v)\r\n", err)
		}
	}
}
<commit_msg>Report failures<commit_after>package app

import (
	"fmt"
	"github.com/callumj/weave/core"
	"github.com/callumj/weave/remote"
	"github.com/callumj/weave/tools"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

func performExtraction(args []string) {
	if len(args) < 3 {
		panicQuitf("Usage: %v ENCRYPTED_FILE KEY_FILE [OUT_DIRECTORY]\r\n", args[0])
	}

	target := args[1]
	keyfile := args[2]

	var eTag string

	matched, _ := regexp.MatchString("^https?:\\/\\/", target)
	if matched {
		if len(args) == 3 {
			panicQuitf("A OUT_DIRECTORY must be specified if using HTTP\r\n")
		} else {
			resp := remote.DownloadRemoteFile(target, args[3])
			if resp == nil {
				panicQuit()
			} else {
				target = resp.FilePath
				eTag = resp.ETag
			}
		}
	}

	var out string

	var success bool
	if len(args) >= 4 {
		out = strings.Join([]string{args[3], "tmp"}, ".")
		success = core.DecryptFile(target, out, keyfile)
	} else {
		out = strings.Replace(target, ".enc", "", 1)
		out = strings.Join([]string{out, "tmp"}, ".")
		if out == target {
			panicQuitf("Cannot determine the out file, please specify")
		}
		success = core.DecryptFile(target, out, keyfile)
	}

	var ensureDirectory = regexp.MustCompile(`(\.(tmp|tgz|tar|gz))+`)
	directory := ensureDirectory.ReplaceAllString(out, "")

	directory, _ = filepath.Abs(directory)

	if !tools.PathExists(directory) {
		os.Mkdir(directory, 0770)
	}

	if success {
		success = core.ExtractArchive(out, directory)
	}

	tools.CleanUpIfNeeded(out)

	if success && len(eTag) != 0 {
		etagfile := fmt.Sprintf("%v/.weave.etag", directory)
		ioutil.WriteFile(etagfile, []byte(eTag), 0775)
	}

	if success {
		runPostExtractionCallback(directory)
	}

	if !success {
		panicQuit()
	}
}

func runPostExtractionCallback(directory string) {
	postExtractionPath := fmt.Sprintf("%v/post_extraction.sh", directory)
	if tools.PathExists(postExtractionPath) {
		bashLoc, _ := exec.LookPath("bash")
		if len(bashLoc) == 0 {
			bashLoc = "/bin/bash"
		}
		cmd := exec.Command(bashLoc, postExtractionPath)
		cmd.Dir = directory
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			panicQuitf("Unable to open STDOUT")
		}
		if err := cmd.Start(); err != nil {
			panicQuitf("Unable to start %v (%v)\r\n", postExtractionPath, err)
		}

		logPath := fmt.Sprintf("%v/post_extraction.log", directory)
		stdoutLogFile, err := os.Create(logPath)
		if err != nil {
			panicQuitf("Unable to open file for logging %v\r\n", logPath)
		}
		defer stdoutLogFile.Close()

		_, err = io.Copy(stdoutLogFile, stdout)
		if err != nil {
			panicQuitf("Failed to copy STDOUT to file (%v)\r\n", err)
		}

		if err := cmd.Wait(); err != nil {
			panicQuitf("Failed finalise command (%v)\r\n", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus 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.

// +build go1.7

// Package api provides clients for the HTTP APIs.
package api

import (
	"context"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// DefaultRoundTripper is used if no RoundTripper is set in Config.
var DefaultRoundTripper http.RoundTripper = &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	DialContext: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}).DialContext,
	TLSHandshakeTimeout: 10 * time.Second,
}

// Config defines configuration parameters for a new client.
type Config struct {
	// The address of the Prometheus to connect to.
	Address string

	// RoundTripper is used by the Client to drive HTTP requests. If not
	// provided, DefaultRoundTripper will be used.
	RoundTripper http.RoundTripper
}

func (cfg *Config) roundTripper() http.RoundTripper {
	if cfg.RoundTripper == nil {
		return DefaultRoundTripper
	}
	return cfg.RoundTripper
}

// Client is the interface for an API client.
type Client interface {
	URL(ep string, args map[string]string) *url.URL
	Do(context.Context, *http.Request) (*http.Response, []byte, error)
}

// NewClient returns a new Client.
//
// It is safe to use the returned Client from multiple goroutines.
func NewClient(cfg Config) (Client, error) {
	u, err := url.Parse(cfg.Address)
	if err != nil {
		return nil, err
	}
	u.Path = strings.TrimRight(u.Path, "/")

	return &httpClient{
		endpoint: u,
		client:   http.Client{Transport: cfg.roundTripper()},
	}, nil
}

type httpClient struct {
	endpoint *url.URL
	client   http.Client
}

func (c *httpClient) URL(ep string, args map[string]string) *url.URL {
	p := path.Join(c.endpoint.Path, ep)

	for arg, val := range args {
		arg = ":" + arg
		p = strings.Replace(p, arg, val, -1)
	}

	u := *c.endpoint
	u.Path = p

	return &u
}

func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
	if ctx != nil {
		req = req.WithContext(ctx)
	}
	resp, err := c.client.Do(req)
	defer func() {
		if resp != nil {
			resp.Body.Close()
		}
	}()

	if err != nil {
		return nil, nil, err
	}

	var body []byte
	done := make(chan struct{})
	go func() {
		body, err = ioutil.ReadAll(resp.Body)
		close(done)
	}()

	select {
	case <-ctx.Done():
		err = resp.Body.Close()
		<-done
		if err == nil {
			err = ctx.Err()
		}
	case <-done:
	}

	return resp, body, err
}
<commit_msg>wait for done before writing to shared resp body (#532)<commit_after>// Copyright 2015 The Prometheus 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.

// +build go1.7

// Package api provides clients for the HTTP APIs.
package api

import (
	"context"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// DefaultRoundTripper is used if no RoundTripper is set in Config.
var DefaultRoundTripper http.RoundTripper = &http.Transport{
	Proxy: http.ProxyFromEnvironment,
	DialContext: (&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}).DialContext,
	TLSHandshakeTimeout: 10 * time.Second,
}

// Config defines configuration parameters for a new client.
type Config struct {
	// The address of the Prometheus to connect to.
	Address string

	// RoundTripper is used by the Client to drive HTTP requests. If not
	// provided, DefaultRoundTripper will be used.
	RoundTripper http.RoundTripper
}

func (cfg *Config) roundTripper() http.RoundTripper {
	if cfg.RoundTripper == nil {
		return DefaultRoundTripper
	}
	return cfg.RoundTripper
}

// Client is the interface for an API client.
type Client interface {
	URL(ep string, args map[string]string) *url.URL
	Do(context.Context, *http.Request) (*http.Response, []byte, error)
}

// NewClient returns a new Client.
//
// It is safe to use the returned Client from multiple goroutines.
func NewClient(cfg Config) (Client, error) {
	u, err := url.Parse(cfg.Address)
	if err != nil {
		return nil, err
	}
	u.Path = strings.TrimRight(u.Path, "/")

	return &httpClient{
		endpoint: u,
		client:   http.Client{Transport: cfg.roundTripper()},
	}, nil
}

type httpClient struct {
	endpoint *url.URL
	client   http.Client
}

func (c *httpClient) URL(ep string, args map[string]string) *url.URL {
	p := path.Join(c.endpoint.Path, ep)

	for arg, val := range args {
		arg = ":" + arg
		p = strings.Replace(p, arg, val, -1)
	}

	u := *c.endpoint
	u.Path = p

	return &u
}

func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
	if ctx != nil {
		req = req.WithContext(ctx)
	}
	resp, err := c.client.Do(req)
	defer func() {
		if resp != nil {
			resp.Body.Close()
		}
	}()

	if err != nil {
		return nil, nil, err
	}

	var body []byte
	done := make(chan struct{})
	go func() {
		body, err = ioutil.ReadAll(resp.Body)
		close(done)
	}()

	select {
	case <-ctx.Done():
		<-done
		err = resp.Body.Close()
		if err == nil {
			err = ctx.Err()
		}
	case <-done:
	}

	return resp, body, err
}
<|endoftext|>


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

package app

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/db"
	tsuruIo "github.com/tsuru/tsuru/io"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/provision"
	"github.com/tsuru/tsuru/repository"
	"github.com/tsuru/tsuru/service"
	"gopkg.in/mgo.v2/bson"
)

type DeployData struct {
	ID          bson.ObjectId `bson:"_id,omitempty"`
	App         string
	Timestamp   time.Time
	Duration    time.Duration
	Commit      string
	Error       string
	Image       string
	Log         string
	User        string
	Origin      string
	CanRollback bool
	RemoveDate  time.Time `bson:",omitempty"`
}

type DiffDeployData struct {
	DeployData
	Diff string
}

func (d *DiffDeployData) MarshalJSON() ([]byte, error) {
	var err error
	if d.Diff == "" {
		d.Diff, err = GetDiffInDeploys(&d.DeployData)
		if err != nil {
			return nil, err
		}
	}
	return json.Marshal(*d)
}

type DeployOptions struct {
	App          *App
	Version      string
	Commit       string
	ArchiveURL   string
	File         io.ReadCloser
	OutputStream io.Writer
	User         string
	Image        string
}

func (app *App) ListDeploys(u *auth.User) ([]DeployData, error) {
	return listDeploys(app, nil, u, 0, 0)
}

// ListDeploys returns the list of deploy that the given user has access to.
//
// If the user does not have acces to any deploy, this function returns an empty
// list and a nil error.
//
// The deploy list can be filtered by app or service.
func ListDeploys(app *App, s *service.Service, u *auth.User, skip, limit int) ([]DeployData, error) {
	return listDeploys(app, s, u, skip, limit)
}

func userHasPermission(u *auth.User, appName string) bool {
	appsByUser, err := List(u, nil)
	if err != nil {
		return false
	}
	for _, app := range appsByUser {
		if app.Name == appName {
			return true
		}
	}
	return false
}

func listDeploys(app *App, s *service.Service, u *auth.User, skip, limit int) ([]DeployData, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	appsByName := set{}
	if app != nil {
		appsByName.Add(app.Name)
	}
	appsByUser := set{}
	if u != nil {
		appsList, _ := List(u, nil)
		for _, a := range appsList {
			appsByUser.Add(a.Name)
		}
	}
	appsByService := set{}
	if s != nil {
		appList := listAppsByService(s.Name)
		for _, a := range appList {
			appsByService.Add(a)
		}
	}
	appsIntersection := appsByService.Intersection(appsByUser.Intersection(appsByName))
	apps := []string{}
	for key := range appsIntersection {
		apps = append(apps, key)
	}
	var list []DeployData
	query := conn.Deploys().Find(bson.M{"app": bson.M{"$in": apps}, "removedate": bson.M{"$exists": false}}).Sort("-timestamp")
	if skip != 0 {
		query = query.Skip(skip)
	}
	if limit != 0 {
		query = query.Limit(limit)
	}
	if err := query.All(&list); err != nil {
		return nil, err
	}
	validImages := set{}
	for _, appName := range apps {
		var imgs []string
		imgs, err = Provisioner.ValidAppImages(appName)
		if err != nil {
			return nil, err
		}
		validImages.Add(imgs...)
	}
	for i := range list {
		list[i].CanRollback = validImages.Includes(list[i].Image)
	}
	return list, err
}

func markDeploysAsRemoved(appName string) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	_, err = conn.Deploys().UpdateAll(
		bson.M{"app": appName, "removedate": bson.M{"$exists": false}},
		bson.M{"$set": bson.M{"removedate": time.Now()}},
	)
	return err
}

func listAppsByService(serviceName string) []string {
	var apps []string
	var instances []service.ServiceInstance
	q := bson.M{"service_name": serviceName}
	conn, err := db.Conn()
	if err != nil {
		return nil
	}
	defer conn.Close()
	conn.ServiceInstances().Find(q).All(&instances)
	for _, instance := range instances {
		for _, app := range instance.Apps {
			apps = append(apps, app)
		}
	}
	return apps
}

func GetDeploy(id string, u *auth.User) (*DeployData, error) {
	var dep DeployData
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	if err := conn.Deploys().FindId(bson.ObjectIdHex(id)).One(&dep); err != nil {
		return nil, err
	}
	if userHasPermission(u, dep.App) {
		return &dep, nil
	}
	return nil, errors.New("Deploy not found.")
}

func GetDiffInDeploys(d *DeployData) (string, error) {
	var list []DeployData
	conn, err := db.Conn()
	if err != nil {
		return "", err
	}
	defer conn.Close()
	if err := conn.Deploys().Find(bson.M{"app": d.App, "_id": bson.M{"$lte": d.ID}}).Sort("-timestamp").Limit(2).All(&list); err != nil {
		return "", err
	}
	if len(list) < 2 {
		return "The deployment must have at least two commits for the diff.", nil
	}
	if list[0].Origin != "git" || list[1].Origin != "git" {
		return fmt.Sprintf("Cannot have diffs between %s based and %s based deployments", list[1].Origin, list[0].Origin), nil
	}
	return repository.Manager().Diff(d.App, list[1].Commit, list[0].Commit)
}

// Deploy runs a deployment of an application. It will first try to run an
// archive based deploy (if opts.ArchiveURL is not empty), and then fallback to
// the Git based deployment.
func Deploy(opts DeployOptions) error {
	var outBuffer bytes.Buffer
	start := time.Now()
	logWriter := LogWriter{App: opts.App}
	logWriter.Async()
	defer logWriter.Close()
	writer := io.MultiWriter(&tsuruIo.NoErrorWriter{Writer: opts.OutputStream}, &outBuffer, &logWriter)
	imageId, err := deployToProvisioner(&opts, writer)
	elapsed := time.Since(start)
	saveErr := saveDeployData(&opts, imageId, outBuffer.String(), elapsed, err)
	if saveErr != nil {
		log.Errorf("WARNING: couldn't save deploy data, deploy opts: %#v", opts)
	}
	if err != nil {
		return err
	}
	err = incrementDeploy(opts.App)
	if err != nil {
		log.Errorf("WARNING: couldn't increment deploy count, deploy opts: %#v", opts)
	}
	if opts.App.UpdatePlatform == true {
		opts.App.SetUpdatePlatform(false)
	}
	return nil
}

func deployToProvisioner(opts *DeployOptions, writer io.Writer) (string, error) {
	if opts.Image != "" {
		if deployer, ok := Provisioner.(provision.ImageDeployer); ok {
			return deployer.ImageDeploy(opts.App, opts.Image, writer)
		}
	}
	if opts.File != nil {
		if deployer, ok := Provisioner.(provision.UploadDeployer); ok {
			return deployer.UploadDeploy(opts.App, opts.File, writer)
		}
	}
	if opts.ArchiveURL != "" {
		if deployer, ok := Provisioner.(provision.ArchiveDeployer); ok {
			return deployer.ArchiveDeploy(opts.App, opts.ArchiveURL, writer)
		}
	}
	return Provisioner.(provision.GitDeployer).GitDeploy(opts.App, opts.Version, writer)
}

func saveDeployData(opts *DeployOptions, imageId, log string, duration time.Duration, deployError error) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	deploy := DeployData{
		App:       opts.App.Name,
		Timestamp: time.Now(),
		Duration:  duration,
		Commit:    opts.Commit,
		Image:     imageId,
		Log:       log,
		User:      opts.User,
	}
	if opts.Commit != "" {
		deploy.Origin = "git"
	} else if opts.Image != "" {
		deploy.Origin = "rollback"
	} else {
		deploy.Origin = "app-deploy"
	}
	if deployError != nil {
		deploy.Error = deployError.Error()
	}
	return conn.Deploys().Insert(deploy)
}

func incrementDeploy(app *App) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Apps().Update(
		bson.M{"name": app.Name},
		bson.M{"$inc": bson.M{"deploys": 1}},
	)
}
<commit_msg>app/deploy: move DeployOptions declaration closer to the Deploy function<commit_after>// Copyright 2015 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/db"
	tsuruIo "github.com/tsuru/tsuru/io"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/provision"
	"github.com/tsuru/tsuru/repository"
	"github.com/tsuru/tsuru/service"
	"gopkg.in/mgo.v2/bson"
)

type DeployData struct {
	ID          bson.ObjectId `bson:"_id,omitempty"`
	App         string
	Timestamp   time.Time
	Duration    time.Duration
	Commit      string
	Error       string
	Image       string
	Log         string
	User        string
	Origin      string
	CanRollback bool
	RemoveDate  time.Time `bson:",omitempty"`
}

type DiffDeployData struct {
	DeployData
	Diff string
}

func (d *DiffDeployData) MarshalJSON() ([]byte, error) {
	var err error
	if d.Diff == "" {
		d.Diff, err = GetDiffInDeploys(&d.DeployData)
		if err != nil {
			return nil, err
		}
	}
	return json.Marshal(*d)
}

func (app *App) ListDeploys(u *auth.User) ([]DeployData, error) {
	return listDeploys(app, nil, u, 0, 0)
}

// ListDeploys returns the list of deploy that the given user has access to.
//
// If the user does not have acces to any deploy, this function returns an empty
// list and a nil error.
//
// The deploy list can be filtered by app or service.
func ListDeploys(app *App, s *service.Service, u *auth.User, skip, limit int) ([]DeployData, error) {
	return listDeploys(app, s, u, skip, limit)
}

func userHasPermission(u *auth.User, appName string) bool {
	appsByUser, err := List(u, nil)
	if err != nil {
		return false
	}
	for _, app := range appsByUser {
		if app.Name == appName {
			return true
		}
	}
	return false
}

func listDeploys(app *App, s *service.Service, u *auth.User, skip, limit int) ([]DeployData, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	appsByName := set{}
	if app != nil {
		appsByName.Add(app.Name)
	}
	appsByUser := set{}
	if u != nil {
		appsList, _ := List(u, nil)
		for _, a := range appsList {
			appsByUser.Add(a.Name)
		}
	}
	appsByService := set{}
	if s != nil {
		appList := listAppsByService(s.Name)
		for _, a := range appList {
			appsByService.Add(a)
		}
	}
	appsIntersection := appsByService.Intersection(appsByUser.Intersection(appsByName))
	apps := []string{}
	for key := range appsIntersection {
		apps = append(apps, key)
	}
	var list []DeployData
	query := conn.Deploys().Find(bson.M{"app": bson.M{"$in": apps}, "removedate": bson.M{"$exists": false}}).Sort("-timestamp")
	if skip != 0 {
		query = query.Skip(skip)
	}
	if limit != 0 {
		query = query.Limit(limit)
	}
	if err := query.All(&list); err != nil {
		return nil, err
	}
	validImages := set{}
	for _, appName := range apps {
		var imgs []string
		imgs, err = Provisioner.ValidAppImages(appName)
		if err != nil {
			return nil, err
		}
		validImages.Add(imgs...)
	}
	for i := range list {
		list[i].CanRollback = validImages.Includes(list[i].Image)
	}
	return list, err
}

func markDeploysAsRemoved(appName string) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	_, err = conn.Deploys().UpdateAll(
		bson.M{"app": appName, "removedate": bson.M{"$exists": false}},
		bson.M{"$set": bson.M{"removedate": time.Now()}},
	)
	return err
}

func listAppsByService(serviceName string) []string {
	var apps []string
	var instances []service.ServiceInstance
	q := bson.M{"service_name": serviceName}
	conn, err := db.Conn()
	if err != nil {
		return nil
	}
	defer conn.Close()
	conn.ServiceInstances().Find(q).All(&instances)
	for _, instance := range instances {
		for _, app := range instance.Apps {
			apps = append(apps, app)
		}
	}
	return apps
}

func GetDeploy(id string, u *auth.User) (*DeployData, error) {
	var dep DeployData
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	if err := conn.Deploys().FindId(bson.ObjectIdHex(id)).One(&dep); err != nil {
		return nil, err
	}
	if userHasPermission(u, dep.App) {
		return &dep, nil
	}
	return nil, errors.New("Deploy not found.")
}

func GetDiffInDeploys(d *DeployData) (string, error) {
	var list []DeployData
	conn, err := db.Conn()
	if err != nil {
		return "", err
	}
	defer conn.Close()
	if err := conn.Deploys().Find(bson.M{"app": d.App, "_id": bson.M{"$lte": d.ID}}).Sort("-timestamp").Limit(2).All(&list); err != nil {
		return "", err
	}
	if len(list) < 2 {
		return "The deployment must have at least two commits for the diff.", nil
	}
	if list[0].Origin != "git" || list[1].Origin != "git" {
		return fmt.Sprintf("Cannot have diffs between %s based and %s based deployments", list[1].Origin, list[0].Origin), nil
	}
	return repository.Manager().Diff(d.App, list[1].Commit, list[0].Commit)
}

type DeployOptions struct {
	App          *App
	Version      string
	Commit       string
	ArchiveURL   string
	File         io.ReadCloser
	OutputStream io.Writer
	User         string
	Image        string
}

// Deploy runs a deployment of an application. It will first try to run an
// archive based deploy (if opts.ArchiveURL is not empty), and then fallback to
// the Git based deployment.
func Deploy(opts DeployOptions) error {
	var outBuffer bytes.Buffer
	start := time.Now()
	logWriter := LogWriter{App: opts.App}
	logWriter.Async()
	defer logWriter.Close()
	writer := io.MultiWriter(&tsuruIo.NoErrorWriter{Writer: opts.OutputStream}, &outBuffer, &logWriter)
	imageId, err := deployToProvisioner(&opts, writer)
	elapsed := time.Since(start)
	saveErr := saveDeployData(&opts, imageId, outBuffer.String(), elapsed, err)
	if saveErr != nil {
		log.Errorf("WARNING: couldn't save deploy data, deploy opts: %#v", opts)
	}
	if err != nil {
		return err
	}
	err = incrementDeploy(opts.App)
	if err != nil {
		log.Errorf("WARNING: couldn't increment deploy count, deploy opts: %#v", opts)
	}
	if opts.App.UpdatePlatform == true {
		opts.App.SetUpdatePlatform(false)
	}
	return nil
}

func deployToProvisioner(opts *DeployOptions, writer io.Writer) (string, error) {
	if opts.Image != "" {
		if deployer, ok := Provisioner.(provision.ImageDeployer); ok {
			return deployer.ImageDeploy(opts.App, opts.Image, writer)
		}
	}
	if opts.File != nil {
		if deployer, ok := Provisioner.(provision.UploadDeployer); ok {
			return deployer.UploadDeploy(opts.App, opts.File, writer)
		}
	}
	if opts.ArchiveURL != "" {
		if deployer, ok := Provisioner.(provision.ArchiveDeployer); ok {
			return deployer.ArchiveDeploy(opts.App, opts.ArchiveURL, writer)
		}
	}
	return Provisioner.(provision.GitDeployer).GitDeploy(opts.App, opts.Version, writer)
}

func saveDeployData(opts *DeployOptions, imageId, log string, duration time.Duration, deployError error) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	deploy := DeployData{
		App:       opts.App.Name,
		Timestamp: time.Now(),
		Duration:  duration,
		Commit:    opts.Commit,
		Image:     imageId,
		Log:       log,
		User:      opts.User,
	}
	if opts.Commit != "" {
		deploy.Origin = "git"
	} else if opts.Image != "" {
		deploy.Origin = "rollback"
	} else {
		deploy.Origin = "app-deploy"
	}
	if deployError != nil {
		deploy.Error = deployError.Error()
	}
	return conn.Deploys().Insert(deploy)
}

func incrementDeploy(app *App) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Apps().Update(
		bson.M{"name": app.Name},
		bson.M{"$inc": bson.M{"deploys": 1}},
	)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/bmizerany/pq"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"time"
)

func main() {
	log.Print("starting ChicagoWorksforYou.com API server")

	router := mux.NewRouter()
	router.HandleFunc("/health_check", HealthCheckHandler)
	router.HandleFunc("/services.json", ServicesHandler)
	router.HandleFunc("/wards/{id}/requests.json", WardRequestsHandler)
	router.HandleFunc("/wards/{id}/counts.json", WardCountsHandler)
	http.ListenAndServe(":4000", router)
}

func WardCountsHandler(response http.ResponseWriter, request *http.Request) {
	// for a given ward, return the number of service requests opened
	// grouped by day, then by service request type

        // sample output
        // $ curl "http://localhost:4000/wards/10/counts.json?service_code=4fd3b167e750846744000005"
        // {
        //   "2013-06-06": 2,
        //   "2013-06-07": 4,
        //   "2013-06-09": 5,
        //   "2013-06-10": 6,
        //   "2013-06-12": 23
        // }
        //
	vars := mux.Vars(request)
	ward_id := vars["id"]
	params := request.URL.Query()

	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	log.Printf("fetching counts for ward %s code %s", ward_id, params["service_code"][0])

	rows, err := db.Query("SELECT COUNT(*), DATE(requested_datetime) as requested_date FROM service_requests WHERE ward = $1 AND duplicate IS NULL AND service_code = $2 GROUP BY DATE(requested_datetime) ORDER BY requested_date;", string(ward_id), params["service_code"][0])
	if err != nil {
		log.Fatal("error fetching data for WardCountsHandler", err)
	}

	type WardCount struct {
		Requested_date time.Time
		Count          int
	}

	var counts []WardCount
	for rows.Next() {
		wc := WardCount{}
		if err := rows.Scan(&wc.Count, &wc.Requested_date); err != nil {
			log.Print("error reading row of ward count", err)
		}

		// trunc the requested time to just date
		counts = append(counts, wc)
	}

	resp := make(map[string]int)

	for _, c := range counts {
		key := c.Requested_date.Format("2006-01-02")
		log.Print("key: ", key)
		resp[key] = c.Count
	}

	jsn, _ := json.MarshalIndent(resp, "", "  ")
	response.Write(jsn)
}

func WardRequestsHandler(response http.ResponseWriter, request *http.Request) {
	// for a given ward, return recent service requests

	vars := mux.Vars(request)
	ward_id := vars["id"]

	log.Print("fetch requests for ward ", ward_id)

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	rows, err := db.Query("SELECT lat,long,ward,police_district,service_request_id,status,service_name,service_code,agency_responsible,address,channel,media_url,requested_datetime,updated_datetime,created_at,updated_at,duplicate,parent_service_request_id,id FROM service_requests WHERE duplicate IS NULL AND ward = $1 ORDER BY updated_at DESC LIMIT 100;", ward_id)

	if err != nil {
		log.Fatal("error fetching data for WardRequestsHandler", err)
	}

	type Open311RequestRow struct {
		Lat, Long                                                                                float64
		Ward, Police_district, Id                                                                                int
		Service_request_id, Status, Service_name, Service_code, Agency_responsible, Address, Channel, Media_url, Duplicate, Parent_service_request_id sql.NullString
		Requested_datetime, Updated_datetime, Created_at, Updated_at                                                                                pq.NullTime // FIXME: should these be proper time objects?
		Extended_attributes                                                                                map[string]interface{}
	}

	var result []Open311RequestRow

	for rows.Next() {
		var row Open311RequestRow
		if err := rows.Scan(&row.Lat, &row.Long, &row.Ward, &row.Police_district,
			&row.Service_request_id, &row.Status, &row.Service_name,
			&row.Service_code, &row.Agency_responsible, &row.Address,
			&row.Channel, &row.Media_url, &row.Requested_datetime,
			&row.Updated_datetime, &row.Created_at, &row.Updated_at,
			&row.Duplicate, &row.Parent_service_request_id,
			&row.Id); err != nil {
			log.Fatal("error reading row", err)
		}

		result = append(result, row)
	}

	jsn, _ := json.MarshalIndent(result, "", "  ")
	response.Write(jsn)
}

func ServicesHandler(response http.ResponseWriter, request *http.Request) {
	// return counts of requests, grouped by service name
	//
	// Sample output:
	//
	// [
	//   {
	//     "Count": 1139,
	//     "Service_code": "4fd3b167e750846744000005",
	//     "Service_name": "Graffiti Removal"
	//   },
	//   {
	//     "Count": 25,
	//     "Service_code": "4fd6e4ece750840569000019",
	//     "Service_name": "Restaurant Complaint"
	//   },
	//
	//  ... snip ...
	//
	// ]

	type ServicesCount struct {
		Count        int
		Service_code string
		Service_name string
	}

	var services []ServicesCount

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	rows, err := db.Query("SELECT COUNT(*), service_code, service_name FROM service_requests WHERE duplicate IS NULL GROUP BY service_code,service_name;")

	if err != nil {
		log.Fatal("error fetching data for ServicesHandler", err)
	}

	for rows.Next() {
		var count int
		var service_code, service_name string

		if err := rows.Scan(&count, &service_code, &service_name); err != nil {
			log.Fatal("error reading row", err)
		}

		row := ServicesCount{Count: count, Service_code: service_code, Service_name: service_name}
		services = append(services, row)
	}

	jsn, _ := json.MarshalIndent(services, "", "  ")
	response.Write(jsn)
}

func HealthCheckHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Add("Content-type", "application/json")

	type HealthCheck struct {
		Count    int
		Database bool
		Healthy  bool
	}

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	health_check := HealthCheck{}

	health_check.Database = db.Ping() == nil

	rows, _ := db.Query("SELECT COUNT(*) FROM service_requests;")
	for rows.Next() {
		if err := rows.Scan(&health_check.Count); err != nil {
			log.Fatal("error fetching count", err)
		}
	}

	// calculate overall health
	health_check.Healthy = health_check.Count > 0 && health_check.Database

	log.Printf("health_check: %+v", health_check)
	if !health_check.Healthy {
		log.Printf("health_check failed")
	}
	jsn, _ := json.Marshal(health_check)
	response.Write(jsn)
}
<commit_msg>Change server port from 4000 to 5000 so I can run Jekyll on port 4000.<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/bmizerany/pq"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"time"
)

func main() {
	log.Print("starting ChicagoWorksforYou.com API server")

	router := mux.NewRouter()
	router.HandleFunc("/health_check", HealthCheckHandler)
	router.HandleFunc("/services.json", ServicesHandler)
	router.HandleFunc("/wards/{id}/requests.json", WardRequestsHandler)
	router.HandleFunc("/wards/{id}/counts.json", WardCountsHandler)
	http.ListenAndServe(":5000", router)
}

func WardCountsHandler(response http.ResponseWriter, request *http.Request) {
	// for a given ward, return the number of service requests opened
	// grouped by day, then by service request type

        // sample output
        // $ curl "http://localhost:5000/wards/10/counts.json?service_code=4fd3b167e750846744000005"
        // {
        //   "2013-06-06": 2,
        //   "2013-06-07": 4,
        //   "2013-06-09": 5,
        //   "2013-06-10": 6,
        //   "2013-06-12": 23
        // }
        //
	vars := mux.Vars(request)
	ward_id := vars["id"]
	params := request.URL.Query()

	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	log.Printf("fetching counts for ward %s code %s", ward_id, params["service_code"][0])

	rows, err := db.Query("SELECT COUNT(*), DATE(requested_datetime) as requested_date FROM service_requests WHERE ward = $1 AND duplicate IS NULL AND service_code = $2 GROUP BY DATE(requested_datetime) ORDER BY requested_date;", string(ward_id), params["service_code"][0])
	if err != nil {
		log.Fatal("error fetching data for WardCountsHandler", err)
	}

	type WardCount struct {
		Requested_date time.Time
		Count          int
	}

	var counts []WardCount
	for rows.Next() {
		wc := WardCount{}
		if err := rows.Scan(&wc.Count, &wc.Requested_date); err != nil {
			log.Print("error reading row of ward count", err)
		}

		// trunc the requested time to just date
		counts = append(counts, wc)
	}

	resp := make(map[string]int)

	for _, c := range counts {
		key := c.Requested_date.Format("2006-01-02")
		log.Print("key: ", key)
		resp[key] = c.Count
	}

	jsn, _ := json.MarshalIndent(resp, "", "  ")
	response.Write(jsn)
}

func WardRequestsHandler(response http.ResponseWriter, request *http.Request) {
	// for a given ward, return recent service requests

	vars := mux.Vars(request)
	ward_id := vars["id"]

	log.Print("fetch requests for ward ", ward_id)

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	rows, err := db.Query("SELECT lat,long,ward,police_district,service_request_id,status,service_name,service_code,agency_responsible,address,channel,media_url,requested_datetime,updated_datetime,created_at,updated_at,duplicate,parent_service_request_id,id FROM service_requests WHERE duplicate IS NULL AND ward = $1 ORDER BY updated_at DESC LIMIT 100;", ward_id)

	if err != nil {
		log.Fatal("error fetching data for WardRequestsHandler", err)
	}

	type Open311RequestRow struct {
		Lat, Long                                                                                float64
		Ward, Police_district, Id                                                                                int
		Service_request_id, Status, Service_name, Service_code, Agency_responsible, Address, Channel, Media_url, Duplicate, Parent_service_request_id sql.NullString
		Requested_datetime, Updated_datetime, Created_at, Updated_at                                                                                pq.NullTime // FIXME: should these be proper time objects?
		Extended_attributes                                                                                map[string]interface{}
	}

	var result []Open311RequestRow

	for rows.Next() {
		var row Open311RequestRow
		if err := rows.Scan(&row.Lat, &row.Long, &row.Ward, &row.Police_district,
			&row.Service_request_id, &row.Status, &row.Service_name,
			&row.Service_code, &row.Agency_responsible, &row.Address,
			&row.Channel, &row.Media_url, &row.Requested_datetime,
			&row.Updated_datetime, &row.Created_at, &row.Updated_at,
			&row.Duplicate, &row.Parent_service_request_id,
			&row.Id); err != nil {
			log.Fatal("error reading row", err)
		}

		result = append(result, row)
	}

	jsn, _ := json.MarshalIndent(result, "", "  ")
	response.Write(jsn)
}

func ServicesHandler(response http.ResponseWriter, request *http.Request) {
	// return counts of requests, grouped by service name
	//
	// Sample output:
	//
	// [
	//   {
	//     "Count": 1139,
	//     "Service_code": "4fd3b167e750846744000005",
	//     "Service_name": "Graffiti Removal"
	//   },
	//   {
	//     "Count": 25,
	//     "Service_code": "4fd6e4ece750840569000019",
	//     "Service_name": "Restaurant Complaint"
	//   },
	//
	//  ... snip ...
	//
	// ]

	type ServicesCount struct {
		Count        int
		Service_code string
		Service_name string
	}

	var services []ServicesCount

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	rows, err := db.Query("SELECT COUNT(*), service_code, service_name FROM service_requests WHERE duplicate IS NULL GROUP BY service_code,service_name;")

	if err != nil {
		log.Fatal("error fetching data for ServicesHandler", err)
	}

	for rows.Next() {
		var count int
		var service_code, service_name string

		if err := rows.Scan(&count, &service_code, &service_name); err != nil {
			log.Fatal("error reading row", err)
		}

		row := ServicesCount{Count: count, Service_code: service_code, Service_name: service_name}
		services = append(services, row)
	}

	jsn, _ := json.MarshalIndent(services, "", "  ")
	response.Write(jsn)
}

func HealthCheckHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Add("Content-type", "application/json")

	type HealthCheck struct {
		Count    int
		Database bool
		Healthy  bool
	}

	// open database
	db, err := sql.Open("postgres", "dbname=cwfy sslmode=disable")
	if err != nil {
		log.Fatal("Cannot open database connection", err)
	}
	defer db.Close()

	health_check := HealthCheck{}

	health_check.Database = db.Ping() == nil

	rows, _ := db.Query("SELECT COUNT(*) FROM service_requests;")
	for rows.Next() {
		if err := rows.Scan(&health_check.Count); err != nil {
			log.Fatal("error fetching count", err)
		}
	}

	// calculate overall health
	health_check.Healthy = health_check.Count > 0 && health_check.Database

	log.Printf("health_check: %+v", health_check)
	if !health_check.Healthy {
		log.Printf("health_check failed")
	}
	jsn, _ := json.Marshal(health_check)
	response.Write(jsn)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"net/http"
	"os/exec"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

func HealthCommand() cli.Command {
	return cli.Command{
		Name:   "health",
		Usage:  "simple healthcheck",
		Action: simpleHealthCheck,
		Flags: []cli.Flag{
			cli.IntFlag{
				Name:  "listen-port,p",
				Usage: "set port to listen on",
				Value: 1620,
			},
			cli.StringFlag{
				Name:  "check-command",
				Usage: "command to execute check",
			},
			cli.StringFlag{
				Name:  "on-failure-command",
				Usage: "command to execute if command fails",
			},
		},
	}
}

type HealthContext struct {
	port           string
	checkCommand   string
	failureCommand string
}

func NewHealthContext(c *cli.Context) *HealthContext {
	context := &HealthContext{}
	context.port = c.String("listen-port")
	context.checkCommand = c.String("check-command")
	context.failureCommand = c.String("on-failure-command")

	return context
}

func simpleHealthCheck(c *cli.Context) {
	context := NewHealthContext(c)
	logrus.Infof("Listening on port: %s", context.port)

	http.Handle("/ping", context)
	err := http.ListenAndServe(fmt.Sprintf(":%s", context.port), nil)
	if err != nil {
		logrus.Fatal(err)
	}
}

func (h *HealthContext) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	message := "OK"
	code := http.StatusOK

	if err := runCommand(h.checkCommand); err != nil {
		code = http.StatusServiceUnavailable
		message = "Failed Health Check. Attempting to Run: " + h.failureCommand
		cmdStatus := "....[Success]"
		if err = runCommand(h.failureCommand); err != nil {
			cmdStatus = "....[Failed]"
		}
		message += cmdStatus
	}

	w.WriteHeader(code)
	fmt.Fprintln(w, message)
}

func runCommand(command string) error {
	if command != "" {
		cmd := exec.Command(command)
		return cmd.Run()
	}
	return nil
}
<commit_msg>Add ability to have subprocess in healthcheck mode<commit_after>package app

import (
	"fmt"
	"net/http"
	"os/exec"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

func HealthCommand() cli.Command {
	return cli.Command{
		Name:   "health",
		Usage:  "simple healthcheck",
		Action: simpleHealthCheck,
		Flags: []cli.Flag{
			cli.IntFlag{
				Name:  "listen-port,p",
				Usage: "set port to listen on",
				Value: 1620,
			},
			cli.StringFlag{
				Name:  "check-command",
				Usage: "command to execute check",
			},
			cli.StringFlag{
				Name:  "on-failure-command",
				Usage: "command to execute if command fails",
			},
		},
	}
}

type HealthContext struct {
	port           string
	checkCommand   string
	failureCommand string
}

func NewHealthContext(c *cli.Context) *HealthContext {
	context := &HealthContext{}
	context.port = c.String("listen-port")
	context.checkCommand = c.String("check-command")
	context.failureCommand = c.String("on-failure-command")

	return context
}

func simpleHealthCheck(c *cli.Context) {
	context := NewHealthContext(c)
	logrus.Infof("Listening on port: %s", context.port)

	http.Handle("/ping", context)
	done := make(chan error)

	go func() {
		done <- http.ListenAndServe(fmt.Sprintf(":%s", context.port), nil)
	}()

	if len(c.Args()) > 0 {
		go func() {
			done <- runCommand(c.Args()[0], c.Args()[1:]...)
		}()
	}

	err := <-done
	if err != nil {
		logrus.Fatal(err)
	}
}

func (h *HealthContext) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	message := "OK"
	code := http.StatusOK

	if err := runCommand(h.checkCommand); err != nil {
		code = http.StatusServiceUnavailable
		message = "Failed Health Check. Attempting to Run: " + h.failureCommand
		cmdStatus := "....[Success]"
		if err = runCommand(h.failureCommand); err != nil {
			cmdStatus = "....[Failed]"
		}
		message += cmdStatus
	}

	w.WriteHeader(code)
	fmt.Fprintln(w, message)
}

func runCommand(command string, args ...string) error {
	if command != "" {
		cmd := exec.Command(command, args...)
		return cmd.Run()
	}
	return nil
}
<|endoftext|>


<commit_before>/**
 * (c) 2014, Tonnerre Lombard <tonnerre@ancient-solutions.com>,
 *	     Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the  name  of  Ancient Solutions  nor  the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Client library for blubberstore end users.
package blubberstore

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"errors"
	"io"
)

// A number of hosts have been contacted but storing the block
// failed on all of them (e.g. because they could not be reached).
// This means that no data has been written whatsoever.
var Err_NoHostsReached = errors.New("Unable to copy the block to even one server - please try again")

// Less than a quorum of the requested nodes have been written.
// This means that the data may disappear again in case of
// outages.
var Err_NoQuorumReached = errors.New("No quorum could be reached")

// The write failed to reach a fully replicated set, but a quorum has
// been achieved. This may be safe to ignore, but the file should
// be distributed better.
var Err_IncompleteWrite = errors.New("Write did not complete to a sufficiently large quorum")

// BlubberStore client which handles replication, quorums and server
// lookups transparently.
type BlubberStoreClient struct {
	directoryClient   *BlubberDirectoryClient
	cert, key, cacert string
	insecure          bool
	errorLog          chan error
}

/*
Create a new Blubber Store client which will talk independently to
the directory service, discover and talk to blubber backends, and
handle timeouts etc.

uri is an URI pointing to the blubber directory.
cert and key are the path to a PEM encoded X.509 certificate and
private key.
cacert is the path to a PEM encoded X.509 CA certificate.
Setting insecure to true disables the use of certificates.
errlog is a channel for reporting non-fatal errors which occur during
operation back to the clients.
*/
func NewBlubberStoreClient(uri, cert, key, cacert string,
	insecure bool, errorlog chan error) (*BlubberStoreClient, error) {
	var dirclient *BlubberDirectoryClient
	var err error

	dirclient, err = NewBlubberDirectoryClient(
		uri, cert, key, cacert, insecure)
	if err != nil {
		return nil, err
	}

	return &BlubberStoreClient{
		directoryClient: dirclient,
		cert:            cert,
		key:             key,
		cacert:          cacert,
		insecure:        insecure,
		errorLog:        errorlog,
	}, nil
}

/*
Write the given data to a blob with the given ID, overwriting it if
specified. This will ensure that there are more than replication/2
copies of the block.
overwrite=false will disable lookups for current block holders.
*/
func (b *BlubberStoreClient) StoreBlock(id []byte, data io.Reader,
	overwrite bool, replication int) error {
	var client *BlubberRPCClient
	var block BlockWithData
	var br BlockReport
	var bs BlockSource
	var attempt int
	var servers []string
	var server string
	var err error

	if overwrite {
		var bid BlockId
		var list *BlockHolderList

		bid.BlockId = make([]byte, len(id))
		copy(bid.BlockId, id)
		list, err = b.directoryClient.LookupBlob(bid)
		if err != nil {
			return err
		}

		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}
	}

	if len(servers) < replication {
		var freeHostReq FreeHostsRequest
		var list *BlockHolderList

		freeHostReq.NumHosts = proto.Int32(int32(replication - len(servers)))
		list, err = b.directoryClient.GetFreeHosts(freeHostReq)
		if err != nil {
			return err
		}

		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}
	}

	// TODO(tonnerre): use the HTTP interface so we can handle large blobs.
	block.BlockId = make([]byte, len(id))
	copy(block.BlockId, id)
	block.Overwrite = proto.Bool(overwrite)
	br.Status = new(BlubberStat)
	br.Status.BlockId = make([]byte, len(id))
	copy(br.Status.BlockId, id)
	br.Server = make([]string, 0)
	_, err = io.ReadFull(data, block.BlockData)
	if err != nil {
		return err
	}

	// TODO(tonnerre): write this to be asynchronous and get the result from
	// a channel.
	for _, server = range servers {
		client, err = NewBlubberRPCClient(
			"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
		if err != nil {
			b.errorLog <- err
			continue
		}

		err = client.StoreBlob(block)
		if err != nil {
			b.errorLog <- err
			continue
		}

		br.Server = append(br.Server, server)
	}

	if len(br.Server) == 0 {
		return Err_NoHostsReached
	}

	// Determine the relevant blob stats of what we've written
	// so far.
	for _, server = range br.Server {
		var bid BlockId
		var stat BlubberStat
		client, err = NewBlubberRPCClient(
			server, b.cert, b.key, b.cacert, b.insecure)
		if err != nil {
			b.errorLog <- err
			continue
		}

		bid.BlockId = make([]byte, len(id))
		copy(bid.BlockId, id)
		stat, err = client.StatBlob(bid)
		if err != nil {
			b.errorLog <- err
			continue
		}

		br.Status = &stat
	}

	if br.Status != nil {
		// Perhaps not the best error code for this?
		return Err_NoQuorumReached
	}

	// First, report our success so far.
	err = b.directoryClient.ReportBlob(br)
	if err != nil {
		b.errorLog <- err
	}

	// Try to copy from the existing set to a bunch of other hosts.
	for len(br.Server) < replication && attempt < replication {
		var freeHostReq FreeHostsRequest
		var list *BlockHolderList
		var sid = attempt % len(br.Server)

		// Try twice as many servers as we had left, since we may just get
		// the ones back which we tried before.
		freeHostReq.NumHosts = proto.Int32(int32(
			2 * (replication - len(br.Server))))
		list, err = b.directoryClient.GetFreeHosts(freeHostReq)
		if err != nil {
			return err
		}

		// Start the server list from scratch.
		servers = make([]string, 0)
		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}

		bs.BlockId = make([]byte, len(id))
		copy(bs.BlockId, id)

		// TODO(tonnerre): write this to be asynchronous and get the result
		// from a channel.
		for _, server = range servers {
			client, err = NewBlubberRPCClient(
				"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
			if err != nil {
				b.errorLog <- err
				continue
			}

			bs.SourceHost = proto.String(br.Server[sid])
			err = client.CopyBlob(bs)
			if err != nil {
				b.errorLog <- err
				continue
			}

			br.Server = append(br.Server, server)
		}

		attempt += 1
	}

	// We give up (or we're done).
	if len(br.Server) < (replication / 2) {
		return Err_NoQuorumReached
	}

	if len(br.Server) < replication {
		return Err_IncompleteWrite
	}

	return nil
}

/*
Read the blob with the given ID.
*/
func (b *BlubberStoreClient) RetrieveBlob(id []byte) (io.Reader, error) {
	var holders *BlockHolderList
	var bid BlockId
	var server string
	var err error

	bid.BlockId = make([]byte, len(id))
	copy(bid.BlockId, id)
	holders, err = b.directoryClient.LookupBlob(bid)
	if err != nil {
		return nil, err
	}

	for _, server = range holders.HostPort {
		var client *BlubberRPCClient
		var bwd BlockWithData

		// TODO(tonnerre): use the HTTP interface so we can handle large
		// blobs.
		client, err = NewBlubberRPCClient(
			"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
		if err != nil {
			b.errorLog <- err
			continue
		}

		bwd, err = client.RetrieveBlob(bid)
		if err != nil {
			b.errorLog <- err
			continue
		}

		return bytes.NewReader(bwd.GetBlockData()), nil
	}

	return nil, Err_NoHostsReached
}
<commit_msg>Don't try to report block stats to the directory.<commit_after>/**
 * (c) 2014, Tonnerre Lombard <tonnerre@ancient-solutions.com>,
 *	     Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the  name  of  Ancient Solutions  nor  the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Client library for blubberstore end users.
package blubberstore

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"errors"
	"io"
)

// A number of hosts have been contacted but storing the block
// failed on all of them (e.g. because they could not be reached).
// This means that no data has been written whatsoever.
var Err_NoHostsReached = errors.New("Unable to copy the block to even one server - please try again")

// Less than a quorum of the requested nodes have been written.
// This means that the data may disappear again in case of
// outages.
var Err_NoQuorumReached = errors.New("No quorum could be reached")

// The write failed to reach a fully replicated set, but a quorum has
// been achieved. This may be safe to ignore, but the file should
// be distributed better.
var Err_IncompleteWrite = errors.New("Write did not complete to a sufficiently large quorum")

// BlubberStore client which handles replication, quorums and server
// lookups transparently.
type BlubberStoreClient struct {
	directoryClient   *BlubberDirectoryClient
	cert, key, cacert string
	insecure          bool
	errorLog          chan error
}

/*
Create a new Blubber Store client which will talk independently to
the directory service, discover and talk to blubber backends, and
handle timeouts etc.

uri is an URI pointing to the blubber directory.
cert and key are the path to a PEM encoded X.509 certificate and
private key.
cacert is the path to a PEM encoded X.509 CA certificate.
Setting insecure to true disables the use of certificates.
errlog is a channel for reporting non-fatal errors which occur during
operation back to the clients.
*/
func NewBlubberStoreClient(uri, cert, key, cacert string,
	insecure bool, errorlog chan error) (*BlubberStoreClient, error) {
	var dirclient *BlubberDirectoryClient
	var err error

	dirclient, err = NewBlubberDirectoryClient(
		uri, cert, key, cacert, insecure)
	if err != nil {
		return nil, err
	}

	return &BlubberStoreClient{
		directoryClient: dirclient,
		cert:            cert,
		key:             key,
		cacert:          cacert,
		insecure:        insecure,
		errorLog:        errorlog,
	}, nil
}

/*
Write the given data to a blob with the given ID, overwriting it if
specified. This will ensure that there are more than replication/2
copies of the block.
overwrite=false will disable lookups for current block holders.
*/
func (b *BlubberStoreClient) StoreBlock(id []byte, data io.Reader,
	overwrite bool, replication int) error {
	var client *BlubberRPCClient
	var block BlockWithData
	var serverlist []string
	var bs BlockSource
	var attempt int
	var servers []string
	var server string
	var err error

	if overwrite {
		var bid BlockId
		var list *BlockHolderList

		bid.BlockId = make([]byte, len(id))
		copy(bid.BlockId, id)
		list, err = b.directoryClient.LookupBlob(bid)
		if err != nil {
			return err
		}

		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}
	}

	if len(servers) < replication {
		var freeHostReq FreeHostsRequest
		var list *BlockHolderList

		freeHostReq.NumHosts = proto.Int32(int32(replication - len(servers)))
		list, err = b.directoryClient.GetFreeHosts(freeHostReq)
		if err != nil {
			return err
		}

		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}
	}

	// TODO(tonnerre): use the HTTP interface so we can handle large blobs.
	block.BlockId = make([]byte, len(id))
	copy(block.BlockId, id)
	serverlist = make([]string, 0)

	_, err = io.ReadFull(data, block.BlockData)
	if err != nil {
		return err
	}

	// TODO(tonnerre): write this to be asynchronous and get the result from
	// a channel.
	for _, server = range servers {
		client, err = NewBlubberRPCClient(
			"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
		if err != nil {
			b.errorLog <- err
			continue
		}

		err = client.StoreBlob(block)
		if err != nil {
			b.errorLog <- err
			continue
		}

		serverlist = append(serverlist, server)
	}

	if len(serverlist) == 0 {
		return Err_NoHostsReached
	}

	// Try to copy from the existing set to a bunch of other hosts.
	for len(serverlist) < replication && attempt < replication {
		var freeHostReq FreeHostsRequest
		var list *BlockHolderList
		var sid = attempt % len(serverlist)

		// Try twice as many servers as we had left, since we may just get
		// the ones back which we tried before.
		freeHostReq.NumHosts = proto.Int32(int32(
			2 * (replication - len(serverlist))))
		list, err = b.directoryClient.GetFreeHosts(freeHostReq)
		if err != nil {
			return err
		}

		// Start the server list from scratch.
		servers = make([]string, 0)
		for _, server = range list.GetHostPort() {
			servers = append(servers, server)
		}

		bs.BlockId = make([]byte, len(id))
		copy(bs.BlockId, id)

		// TODO(tonnerre): write this to be asynchronous and get the result
		// from a channel.
		for _, server = range servers {
			client, err = NewBlubberRPCClient(
				"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
			if err != nil {
				b.errorLog <- err
				continue
			}

			bs.SourceHost = proto.String(serverlist[sid])
			err = client.CopyBlob(bs)
			if err != nil {
				b.errorLog <- err
				continue
			}

			serverlist = append(serverlist, server)
		}

		attempt += 1
	}

	// We give up (or we're done).
	if len(serverlist) < (replication / 2) {
		return Err_NoQuorumReached
	}

	if len(serverlist) < replication {
		return Err_IncompleteWrite
	}

	return nil
}

/*
Read the blob with the given ID.
*/
func (b *BlubberStoreClient) RetrieveBlob(id []byte) (io.Reader, error) {
	var holders *BlockHolderList
	var bid BlockId
	var server string
	var err error

	bid.BlockId = make([]byte, len(id))
	copy(bid.BlockId, id)
	holders, err = b.directoryClient.LookupBlob(bid)
	if err != nil {
		return nil, err
	}

	for _, server = range holders.HostPort {
		var client *BlubberRPCClient
		var bwd BlockWithData

		// TODO(tonnerre): use the HTTP interface so we can handle large
		// blobs.
		client, err = NewBlubberRPCClient(
			"tcp://"+server, b.cert, b.key, b.cacert, b.insecure)
		if err != nil {
			b.errorLog <- err
			continue
		}

		bwd, err = client.RetrieveBlob(bid)
		if err != nil {
			b.errorLog <- err
			continue
		}

		return bytes.NewReader(bwd.GetBlockData()), nil
	}

	return nil, Err_NoHostsReached
}
<|endoftext|>


<commit_before>package errcheck

import (
	"fmt"
	"go/build"
	"path/filepath"
)

// findPackage finds a package.
// path is first tried as an import path and if the package is not found, as a filesystem path.
func findPackage(path string) (*build.Package, error) {
	var (
		err1, err2 error
		pkg        *build.Package
	)

	ctx := build.Default
	ctx.CgoEnabled = false

	// First try to treat path as import path...
	pkg, err1 = ctx.Import(path, ".", 0)
	if err1 != nil {
		if _, ok := err1.(*build.NoGoError); ok {
			return nil, err1
		}
		// ... then attempt as file path
		pkg, err2 = ctx.ImportDir(path, 0)
	}

	if err2 != nil {
		// Print both errors so the user can see in what ways the
		// package lookup failed.
		return nil, fmt.Errorf("could not import %s: %s\n%s", path, err1, err2)
	}

	return pkg, nil
}

// getFiles returns all the Go files found in a package
func getFiles(pkg *build.Package) []string {
	files := make([]string, len(pkg.GoFiles))
	for i, fileName := range pkg.GoFiles {
		files[i] = filepath.Join(pkg.Dir, fileName)
	}
	return files
}
<commit_msg>remove util.go<commit_after><|endoftext|>