<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	flag "github.com/spf13/pflag"
	"golang.org/x/net/context"
	clientset "k8s.io/client-go/1.5/kubernetes"
	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/api/v1"
	"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
	restclient "k8s.io/client-go/1.5/rest"
	"k8s.io/client-go/1.5/tools/cache"
	"k8s.io/client-go/1.5/tools/clientcmd"

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

const (
	resyncPeriod = 5 * time.Minute
	metricsPath  = "/metrics"
	healthzPath  = "/healthz"
)

var (
	flags = flag.NewFlagSet("", flag.ExitOnError)

	inCluster = flags.Bool("in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)

	apiserver = flags.String("apiserver", "", `The URL of the apiserver to use as a master`)

	kubeconfig = flags.String("kubeconfig", "", "absolute path to the kubeconfig file")

	help = flags.BoolP("help", "h", false, "Print help text")

	port = flags.Int("port", 80, `Port to expose metrics on.`)
)

func main() {
	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if *help {
		flags.Usage()
		os.Exit(0)
	}

	if *apiserver == "" && !(*inCluster) {
		glog.Fatalf("--apiserver not set and --in-cluster is false; apiserver must be set to a valid URL")
	}
	glog.Infof("apiServer set to: %v", *apiserver)

	proc.StartReaper()

	kubeClient, err := createKubeClient()
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	initializeMetricCollection(kubeClient)
	metricsServer()
}

func createKubeClient() (kubeClient clientset.Interface, err error) {
	glog.Infof("Creating client")
	if *inCluster {
		config, err := restclient.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if *apiserver != "" {
			config.Host = *apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = *kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("testing communication with server")
	_, err = kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}

	return kubeClient, nil
}

func metricsServer() {
	// Address to listen on for web interface and telemetry
	listenAddress := fmt.Sprintf(":%d", *port)

	glog.Infof("Starting metrics server: %s", listenAddress)
	// Add metricsPath
	http.Handle(metricsPath, prometheus.UninstrumentedHandler())
	// Add healthzPath
	http.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, nil))
}

type DaemonSetLister func() ([]v1beta1.DaemonSet, error)

func (l DaemonSetLister) List() ([]v1beta1.DaemonSet, error) {
	return l()
}

type DeploymentLister func() ([]v1beta1.Deployment, error)

func (l DeploymentLister) List() ([]v1beta1.Deployment, error) {
	return l()
}

type PodLister func() ([]v1.Pod, error)

func (l PodLister) List() ([]v1.Pod, error) {
	return l()
}

type NodeLister func() (v1.NodeList, error)

func (l NodeLister) List() (v1.NodeList, error) {
	return l()
}

type ResourceQuotaLister func() (v1.ResourceQuotaList, error)

func (l ResourceQuotaLister) List() (v1.ResourceQuotaList, error) {
	return l()
}

// initializeMetricCollection creates and starts informers and initializes and
// registers metrics for collection.
func initializeMetricCollection(kubeClient clientset.Interface) {
	cclient := kubeClient.Core().GetRESTClient()
	eclient := kubeClient.Extensions().GetRESTClient()

	dslw := cache.NewListWatchFromClient(eclient, "daemonsets", api.NamespaceAll, nil)
	dlw := cache.NewListWatchFromClient(eclient, "deployments", api.NamespaceAll, nil)
	plw := cache.NewListWatchFromClient(cclient, "pods", api.NamespaceAll, nil)
	nlw := cache.NewListWatchFromClient(cclient, "nodes", api.NamespaceAll, nil)
	rqlw := cache.NewListWatchFromClient(cclient, "resourcequotas", api.NamespaceAll, nil)

	dsinf := cache.NewSharedInformer(dslw, &v1beta1.DaemonSet{}, resyncPeriod)
	dinf := cache.NewSharedInformer(dlw, &v1beta1.Deployment{}, resyncPeriod)
	pinf := cache.NewSharedInformer(plw, &v1.Pod{}, resyncPeriod)
	ninf := cache.NewSharedInformer(nlw, &v1.Node{}, resyncPeriod)
	rqinf := cache.NewSharedInformer(rqlw, &v1.ResourceQuota{}, resyncPeriod)

	dsLister := DaemonSetLister(func() (daemonsets []v1beta1.DaemonSet, err error) {
		for _, c := range dsinf.GetStore().List() {
			daemonsets = append(daemonsets, *(c.(*v1beta1.DaemonSet)))
		}
		return daemonsets, nil
	})

	dplLister := DeploymentLister(func() (deployments []v1beta1.Deployment, err error) {
		for _, c := range dinf.GetStore().List() {
			deployments = append(deployments, *(c.(*v1beta1.Deployment)))
		}
		return deployments, nil
	})

	podLister := PodLister(func() (pods []v1.Pod, err error) {
		for _, m := range pinf.GetStore().List() {
			pods = append(pods, *m.(*v1.Pod))
		}
		return pods, nil
	})

	nodeLister := NodeLister(func() (machines v1.NodeList, err error) {
		for _, m := range ninf.GetStore().List() {
			machines.Items = append(machines.Items, *(m.(*v1.Node)))
		}
		return machines, nil
	})

	resourceQuotaLister := ResourceQuotaLister(func() (quotas v1.ResourceQuotaList, err error) {
		for _, rq := range rqinf.GetStore().List() {
			quotas.Items = append(quotas.Items, *(rq.(*v1.ResourceQuota)))
		}
		return quotas, nil
	})

	prometheus.MustRegister(&daemonsetCollector{store: dsLister})
	prometheus.MustRegister(&deploymentCollector{store: dplLister})
	prometheus.MustRegister(&podCollector{store: podLister})
	prometheus.MustRegister(&nodeCollector{store: nodeLister})
	prometheus.MustRegister(&resourceQuotaCollector{store: resourceQuotaLister})

	go dsinf.Run(context.Background().Done())
	go dinf.Run(context.Background().Done())
	go pinf.Run(context.Background().Done())
	go ninf.Run(context.Background().Done())
	go rqinf.Run(context.Background().Done())

}
<commit_msg>If --cluster-info is false, kubeconfig is valid<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	flag "github.com/spf13/pflag"
	"golang.org/x/net/context"
	clientset "k8s.io/client-go/1.5/kubernetes"
	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/api/v1"
	"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
	restclient "k8s.io/client-go/1.5/rest"
	"k8s.io/client-go/1.5/tools/cache"
	"k8s.io/client-go/1.5/tools/clientcmd"

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

const (
	resyncPeriod = 5 * time.Minute
	metricsPath  = "/metrics"
	healthzPath  = "/healthz"
)

var (
	flags = flag.NewFlagSet("", flag.ExitOnError)

	inCluster = flags.Bool("in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)

	apiserver = flags.String("apiserver", "", `The URL of the apiserver to use as a master`)

	kubeconfig = flags.String("kubeconfig", "", "absolute path to the kubeconfig file")

	help = flags.BoolP("help", "h", false, "Print help text")

	port = flags.Int("port", 80, `Port to expose metrics on.`)
)

func main() {
	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if *help {
		flags.Usage()
		os.Exit(0)
	}

	if isNotExists(*kubeconfig) && !(*inCluster) {
		glog.Fatalf("kubeconfig invalid and --in-cluster is false; kubeconfig must be set to a valid file(kubeconfig default file name: $HOME/.kube/config)")
	}
	glog.Infof("apiServer set to: %v", *apiserver)

	proc.StartReaper()

	kubeClient, err := createKubeClient()
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	initializeMetricCollection(kubeClient)
	metricsServer()
}

func isNotExists(file string) bool {
	if file == "" {
		file = clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
	}
	_, err := os.Stat(file)
	return os.IsNotExist(err)
}

func createKubeClient() (kubeClient clientset.Interface, err error) {
	glog.Infof("Creating client")
	if *inCluster {
		config, err := restclient.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if *apiserver != "" {
			config.Host = *apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = *kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("testing communication with server")
	_, err = kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}

	return kubeClient, nil
}

func metricsServer() {
	// Address to listen on for web interface and telemetry
	listenAddress := fmt.Sprintf(":%d", *port)

	glog.Infof("Starting metrics server: %s", listenAddress)
	// Add metricsPath
	http.Handle(metricsPath, prometheus.UninstrumentedHandler())
	// Add healthzPath
	http.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, nil))
}

type DaemonSetLister func() ([]v1beta1.DaemonSet, error)

func (l DaemonSetLister) List() ([]v1beta1.DaemonSet, error) {
	return l()
}

type DeploymentLister func() ([]v1beta1.Deployment, error)

func (l DeploymentLister) List() ([]v1beta1.Deployment, error) {
	return l()
}

type PodLister func() ([]v1.Pod, error)

func (l PodLister) List() ([]v1.Pod, error) {
	return l()
}

type NodeLister func() (v1.NodeList, error)

func (l NodeLister) List() (v1.NodeList, error) {
	return l()
}

type ResourceQuotaLister func() (v1.ResourceQuotaList, error)

func (l ResourceQuotaLister) List() (v1.ResourceQuotaList, error) {
	return l()
}

// initializeMetricCollection creates and starts informers and initializes and
// registers metrics for collection.
func initializeMetricCollection(kubeClient clientset.Interface) {
	cclient := kubeClient.Core().GetRESTClient()
	eclient := kubeClient.Extensions().GetRESTClient()

	dslw := cache.NewListWatchFromClient(eclient, "daemonsets", api.NamespaceAll, nil)
	dlw := cache.NewListWatchFromClient(eclient, "deployments", api.NamespaceAll, nil)
	plw := cache.NewListWatchFromClient(cclient, "pods", api.NamespaceAll, nil)
	nlw := cache.NewListWatchFromClient(cclient, "nodes", api.NamespaceAll, nil)
	rqlw := cache.NewListWatchFromClient(cclient, "resourcequotas", api.NamespaceAll, nil)

	dsinf := cache.NewSharedInformer(dslw, &v1beta1.DaemonSet{}, resyncPeriod)
	dinf := cache.NewSharedInformer(dlw, &v1beta1.Deployment{}, resyncPeriod)
	pinf := cache.NewSharedInformer(plw, &v1.Pod{}, resyncPeriod)
	ninf := cache.NewSharedInformer(nlw, &v1.Node{}, resyncPeriod)
	rqinf := cache.NewSharedInformer(rqlw, &v1.ResourceQuota{}, resyncPeriod)

	dsLister := DaemonSetLister(func() (daemonsets []v1beta1.DaemonSet, err error) {
		for _, c := range dsinf.GetStore().List() {
			daemonsets = append(daemonsets, *(c.(*v1beta1.DaemonSet)))
		}
		return daemonsets, nil
	})

	dplLister := DeploymentLister(func() (deployments []v1beta1.Deployment, err error) {
		for _, c := range dinf.GetStore().List() {
			deployments = append(deployments, *(c.(*v1beta1.Deployment)))
		}
		return deployments, nil
	})

	podLister := PodLister(func() (pods []v1.Pod, err error) {
		for _, m := range pinf.GetStore().List() {
			pods = append(pods, *m.(*v1.Pod))
		}
		return pods, nil
	})

	nodeLister := NodeLister(func() (machines v1.NodeList, err error) {
		for _, m := range ninf.GetStore().List() {
			machines.Items = append(machines.Items, *(m.(*v1.Node)))
		}
		return machines, nil
	})

	resourceQuotaLister := ResourceQuotaLister(func() (quotas v1.ResourceQuotaList, err error) {
		for _, rq := range rqinf.GetStore().List() {
			quotas.Items = append(quotas.Items, *(rq.(*v1.ResourceQuota)))
		}
		return quotas, nil
	})

	prometheus.MustRegister(&daemonsetCollector{store: dsLister})
	prometheus.MustRegister(&deploymentCollector{store: dplLister})
	prometheus.MustRegister(&podCollector{store: podLister})
	prometheus.MustRegister(&nodeCollector{store: nodeLister})
	prometheus.MustRegister(&resourceQuotaCollector{store: resourceQuotaLister})

	go dsinf.Run(context.Background().Done())
	go dinf.Run(context.Background().Done())
	go pinf.Run(context.Background().Done())
	go ninf.Run(context.Background().Done())
	go rqinf.Run(context.Background().Done())

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
)

func Err(s string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "error:"+s+"\n", args...)
}

func main() {
	flag.Parse()
	pkgName := flag.Arg(0)
	if pkgName == "" {
		Err("you must specify a package")
		flag.Usage()
		os.Exit(1)
	}

	pkg, err := build.Import(pkgName, ".", 0)
	if err != nil {
		Err("could not import %s: %s", pkgName, err)
		os.Exit(1)
	}

	files := make([]string, len(pkg.GoFiles))
	for i, fileName := range pkg.GoFiles {
		files[i] = filepath.Join(pkg.Dir, fileName)
	}

	if err := checkFiles(files); err != nil {
		Err("failed to check package: %s", err)
		os.Exit(1)
	}
}

type file struct {
	fset  *token.FileSet
	name  string
	ast   *ast.File
	lines [][]byte
}

func parseFile(fset *token.FileSet, fileName string) (f file, err error) {
	rd, err := os.Open(fileName)
	if err != nil {
		return f, err
	}
	defer rd.Close()

	data, err := ioutil.ReadAll(rd)
	if err != nil {
		return f, err
	}

	astFile, err := parser.ParseFile(fset, fileName, bytes.NewReader(data), parser.ParseComments)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	lines := bytes.Split(data, []byte("\n"))
	f = file{fset: fset, name: fileName, ast: astFile, lines: lines}
	return f, nil
}

func typeCheck(fset *token.FileSet, astFiles []*ast.File) (map[*ast.CallExpr]types.Type, map[*ast.Ident]types.Object, error) {
	callTypes := make(map[*ast.CallExpr]types.Type)
	identObjs := make(map[*ast.Ident]types.Object)

	exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
		call, ok := x.(*ast.CallExpr)
		if !ok {
			return
		}
		callTypes[call] = typ
	}
	identFn := func(id *ast.Ident, obj types.Object) {
		identObjs[id] = obj
	}
	context := types.Context{
		Expr:  exprFn,
		Ident: identFn,
	}
	_, err := context.Check(fset, astFiles)
	return callTypes, identObjs, err
}

type checker struct {
	fset      *token.FileSet
	files     map[string]file
	callTypes map[*ast.CallExpr]types.Type
	identObjs map[*ast.Ident]types.Object
}

func (c checker) Visit(node ast.Node) ast.Visitor {
	n, ok := node.(*ast.ExprStmt)
	if !ok {
		return c
	}

	// Check for a call expression
	call, ok := n.X.(*ast.CallExpr)
	if !ok {
		return c
	}

	var id *ast.Ident
	switch exp := call.Fun.(type) {
	case (*ast.Ident):
		id = exp
	case (*ast.SelectorExpr):
		id = exp.Sel
	default:
		fmt.Fprintf(os.Stderr, "unknown call: %T %+v\n", exp, exp)
		return c
	}

	callType := c.callTypes[call]

	unchecked := false

	switch t := callType.(type) {
	case *types.NamedType:
		// Single return
		if isErrorType(t.Obj) {
			unchecked = true
		}
	case *types.Result:
		// Multiple returns
		for _, v := range t.Values {
			nt, ok := v.Type.(*types.NamedType)
			if !ok {
				continue
			}
			if isErrorType(nt.Obj) {
				unchecked = true
				break
			}
		}
	}

	if unchecked {
		pos := c.fset.Position(id.NamePos)
		fmt.Fprintf(os.Stdout, "%s %s\n", pos, c.files[pos.Filename].lines[pos.Line-1])
	}
	return c
}

func checkFiles(fileNames []string) error {
	fset := token.NewFileSet()
	astFiles := make([]*ast.File, len(fileNames))
	files := make(map[string]file, len(fileNames))

	for i, fileName := range fileNames {
		f, err := parseFile(fset, fileName)
		if err != nil {
			return fmt.Errorf("could not parse %s: %s", fileName, err)
		}
		files[fileName] = f
		astFiles[i] = f.ast
	}

	callTypes, identObjs, err := typeCheck(fset, astFiles)
	if err != nil {
		return fmt.Errorf("could not type check: %s", err)
	}

	visitor := checker{fset, files, callTypes, identObjs}
	for _, astFile := range astFiles {
		ast.Walk(visitor, astFile)
	}

	return nil
}

type obj interface {
	GetPkg() *types.Package
	GetName() string
}

func isErrorType(v obj) bool {
	return v.GetPkg() == nil && v.GetName() == "error"
}
<commit_msg>Basic ignore. Ignore the fmt package.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
)

func Err(s string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "error:"+s+"\n", args...)
}

func main() {
	flag.Parse()
	pkgName := flag.Arg(0)
	if pkgName == "" {
		Err("you must specify a package")
		flag.Usage()
		os.Exit(1)
	}

	pkg, err := build.Import(pkgName, ".", 0)
	if err != nil {
		Err("could not import %s: %s", pkgName, err)
		os.Exit(1)
	}

	files := make([]string, len(pkg.GoFiles))
	for i, fileName := range pkg.GoFiles {
		files[i] = filepath.Join(pkg.Dir, fileName)
	}

	if err := checkFiles(files); err != nil {
		Err("failed to check package: %s", err)
		os.Exit(1)
	}
}

type file struct {
	fset  *token.FileSet
	name  string
	ast   *ast.File
	lines [][]byte
}

func parseFile(fset *token.FileSet, fileName string) (f file, err error) {
	rd, err := os.Open(fileName)
	if err != nil {
		return f, err
	}
	defer rd.Close()

	data, err := ioutil.ReadAll(rd)
	if err != nil {
		return f, err
	}

	astFile, err := parser.ParseFile(fset, fileName, bytes.NewReader(data), parser.ParseComments)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	lines := bytes.Split(data, []byte("\n"))
	f = file{fset: fset, name: fileName, ast: astFile, lines: lines}
	return f, nil
}

func typeCheck(fset *token.FileSet, astFiles []*ast.File) (map[*ast.CallExpr]types.Type, map[*ast.Ident]types.Object, error) {
	callTypes := make(map[*ast.CallExpr]types.Type)
	identObjs := make(map[*ast.Ident]types.Object)

	exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
		call, ok := x.(*ast.CallExpr)
		if !ok {
			return
		}
		callTypes[call] = typ
	}
	identFn := func(id *ast.Ident, obj types.Object) {
		identObjs[id] = obj
	}
	context := types.Context{
		Expr:  exprFn,
		Ident: identFn,
	}
	_, err := context.Check(fset, astFiles)
	return callTypes, identObjs, err
}

type checker struct {
	fset      *token.FileSet
	files     map[string]file
	callTypes map[*ast.CallExpr]types.Type
	identObjs map[*ast.Ident]types.Object
	ignorePkg map[string]bool
}

func (c checker) Visit(node ast.Node) ast.Visitor {
	n, ok := node.(*ast.ExprStmt)
	if !ok {
		return c
	}

	// Check for a call expression
	call, ok := n.X.(*ast.CallExpr)
	if !ok {
		return c
	}

	var id *ast.Ident
	switch exp := call.Fun.(type) {
	case (*ast.Ident):
		id = exp
	case (*ast.SelectorExpr):
		id = exp.Sel
	default:
		fmt.Fprintf(os.Stderr, "unknown call: %T %+v\n", exp, exp)
		return c
	}

	if obj := c.identObjs[id]; obj != nil {
		if pkg := obj.GetPkg(); pkg != nil && c.ignorePkg[pkg.Path] {
			return c
		}
	}
	callType := c.callTypes[call]

	unchecked := false

	switch t := callType.(type) {
	case *types.NamedType:
		// Single return
		if isErrorType(t.Obj) {
			unchecked = true
		}
	case *types.Result:
		// Multiple returns
		for _, v := range t.Values {
			nt, ok := v.Type.(*types.NamedType)
			if !ok {
				continue
			}
			if isErrorType(nt.Obj) {
				unchecked = true
				break
			}
		}
	}

	if unchecked {
		pos := c.fset.Position(id.NamePos)
		fmt.Fprintf(os.Stdout, "%s %s\n", pos, c.files[pos.Filename].lines[pos.Line-1])
	}
	return c
}

func checkFiles(fileNames []string) error {
	fset := token.NewFileSet()
	astFiles := make([]*ast.File, len(fileNames))
	files := make(map[string]file, len(fileNames))

	for i, fileName := range fileNames {
		f, err := parseFile(fset, fileName)
		if err != nil {
			return fmt.Errorf("could not parse %s: %s", fileName, err)
		}
		files[fileName] = f
		astFiles[i] = f.ast
	}

	callTypes, identObjs, err := typeCheck(fset, astFiles)
	if err != nil {
		return fmt.Errorf("could not type check: %s", err)
	}

	ignorePkg := make(map[string]bool)
	ignorePkg["fmt"] = true

	visitor := checker{fset, files, callTypes, identObjs, ignorePkg}
	for _, astFile := range astFiles {
		ast.Walk(visitor, astFile)
	}

	return nil
}

type obj interface {
	GetPkg() *types.Package
	GetName() string
}

func isErrorType(v obj) bool {
	return v.GetPkg() == nil && v.GetName() == "error"
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/sha1"
	"encoding/hex"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"

	"code.google.com/p/go.net/idna"
	_ "github.com/domainr/go-whois/servers"
	"github.com/domainr/go-whois/whois"
)

var (
	v, quick       bool
	oneZone        string
	concurrency    int
	zones          []string
	prefixes       []string
	_, _file, _, _ = runtime.Caller(0)
	_dir           = filepath.Dir(_file)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only query a shorter subset of zones")
	flag.StringVar(&oneZone, "zone", "", "Only query a specific zone")
	flag.IntVar(&concurrency, "concurrency", 32, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = []string{"com", "net", "org", "co", "io", "nr"}
		concurrency = 4 // Don’t slam the .org whois server
	}

	// One zone?
	if oneZone != "" {
		fmt.Fprintf(os.Stderr, "Querying single zone: %s\n", oneZone)
		zones = []string{oneZone}
		concurrency = 1
	}

	re := regexp.MustCompile(`^[^\.]+\.`)

	domains := make(map[string]bool, len(zones)*len(prefixes))
	for _, zone := range zones {
		for _, prefix := range prefixes {
			domain := prefix + "." + zone
			domains[domain] = true
			req, err := whois.Resolve(domain)
			if err == nil {
				hostParent := re.ReplaceAllLiteralString(req.Host, "")
				if _, ok := domains[hostParent]; !ok && hostParent != "" {
					fmt.Fprintf(os.Stderr, "  + %s\n", hostParent)
					domains[hostParent] = true
				}
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Querying whois for %d domains (%d prefixes × %d zones + extras)\n", len(domains), len(prefixes), len(zones))

	responses := make(chan *whois.Response)
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	for domain, _ := range domains {
		go func(domain string) {
			var res *whois.Response

			limiter <- struct{}{} // acquire semaphore
			defer func() {        // release semaphore
				responses <- res
				<-limiter
			}()

			req, err := whois.Resolve(domain)
			if err != nil {
				return
			}

			if v {
				fmt.Fprintf(os.Stderr, "Fetching %s from %s\n", req.Query, req.Host)
			}
			res, err = req.Fetch()
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error fetching whois for %s: %s\n", req.Query, err)
				return
			}
		}(domain)
	}

	// Collect from goroutines
	var wg sync.WaitGroup
	wg.Add(len(domains))
	for i := 0; i < len(domains); i++ {
		go func() {
			res := <-responses
			defer wg.Done()

			if res == nil {
				return
			}

			if res.Host == "" {
				fmt.Fprintf(os.Stderr, "Response for %q had no host\n", res.Query)
				return
			}

			if len(res.Body) == 0 {
				fmt.Fprintf(os.Stderr, "Response for %q had empty body\n", res.Query)
				return
			}

			dir := filepath.Join(_dir, "data", "responses", res.Host)
			err := os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response directory for %s: %s\n", res.Host, err)
				return
			}

			fn := filepath.Join(dir, (sha1hex(res.Body) + ".mime"))
			f, err := os.Create(fn)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response file for %s: %s\n", res.Query, err)
				return
			}
			defer f.Close()
			res.WriteMIME(f)
		}()
	}
	wg.Wait()

	return nil
}

var whitespaceAndComments = regexp.MustCompile(`\s+|#.+$`)

func readLines(fn string) ([]string, error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	f, err := os.Open(filepath.Join(_dir, "data", fn))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var out []string
	s := bufio.NewScanner(f)
	for s.Scan() {
		line := whitespaceAndComments.ReplaceAllLiteralString(s.Text(), "")
		if line == "" {
			continue
		}
		if line, ierr := idna.ToASCII(line); ierr == nil {
			out = append(out, line)
		}
	}
	return out, s.Err()
}

func sha1hex(buf []byte) string {
	h := sha1.New()
	h.Write(buf)
	return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}
<commit_msg>Scan kr and jp in -quick mode for JIS and UTF-8 responses.<commit_after>package main

import (
	"bufio"
	"crypto/sha1"
	"encoding/hex"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"

	"code.google.com/p/go.net/idna"
	_ "github.com/domainr/go-whois/servers"
	"github.com/domainr/go-whois/whois"
)

var (
	v, quick       bool
	oneZone        string
	concurrency    int
	zones          []string
	prefixes       []string
	_, _file, _, _ = runtime.Caller(0)
	_dir           = filepath.Dir(_file)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only query a shorter subset of zones")
	flag.StringVar(&oneZone, "zone", "", "Only query a specific zone")
	flag.IntVar(&concurrency, "concurrency", 32, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = []string{"com", "net", "org", "co", "io", "nr", "kr", "jp"}
		concurrency = 4 // Don’t slam the .org whois server
	}

	// One zone?
	if oneZone != "" {
		fmt.Fprintf(os.Stderr, "Querying single zone: %s\n", oneZone)
		zones = []string{oneZone}
		concurrency = 1
	}

	re := regexp.MustCompile(`^[^\.]+\.`)

	domains := make(map[string]bool, len(zones)*len(prefixes))
	for _, zone := range zones {
		for _, prefix := range prefixes {
			domain := prefix + "." + zone
			domains[domain] = true
			req, err := whois.Resolve(domain)
			if err == nil {
				hostParent := re.ReplaceAllLiteralString(req.Host, "")
				if _, ok := domains[hostParent]; !ok && hostParent != "" {
					fmt.Fprintf(os.Stderr, "  + %s\n", hostParent)
					domains[hostParent] = true
				}
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Querying whois for %d domains (%d prefixes × %d zones + extras)\n", len(domains), len(prefixes), len(zones))

	responses := make(chan *whois.Response)
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	for domain, _ := range domains {
		go func(domain string) {
			var res *whois.Response

			limiter <- struct{}{} // acquire semaphore
			defer func() {        // release semaphore
				responses <- res
				<-limiter
			}()

			req, err := whois.Resolve(domain)
			if err != nil {
				return
			}

			if v {
				fmt.Fprintf(os.Stderr, "Fetching %s from %s\n", req.Query, req.Host)
			}
			res, err = req.Fetch()
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error fetching whois for %s: %s\n", req.Query, err)
				return
			}
		}(domain)
	}

	// Collect from goroutines
	var wg sync.WaitGroup
	wg.Add(len(domains))
	for i := 0; i < len(domains); i++ {
		go func() {
			res := <-responses
			defer wg.Done()

			if res == nil {
				return
			}

			if res.Host == "" {
				fmt.Fprintf(os.Stderr, "Response for %q had no host\n", res.Query)
				return
			}

			if len(res.Body) == 0 {
				fmt.Fprintf(os.Stderr, "Response for %q had empty body\n", res.Query)
				return
			}

			dir := filepath.Join(_dir, "data", "responses", res.Host)
			err := os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response directory for %s: %s\n", res.Host, err)
				return
			}

			fn := filepath.Join(dir, (sha1hex(res.Body) + ".mime"))
			f, err := os.Create(fn)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response file for %s: %s\n", res.Query, err)
				return
			}
			defer f.Close()
			res.WriteMIME(f)
		}()
	}
	wg.Wait()

	return nil
}

var whitespaceAndComments = regexp.MustCompile(`\s+|#.+$`)

func readLines(fn string) ([]string, error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	f, err := os.Open(filepath.Join(_dir, "data", fn))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var out []string
	s := bufio.NewScanner(f)
	for s.Scan() {
		line := whitespaceAndComments.ReplaceAllLiteralString(s.Text(), "")
		if line == "" {
			continue
		}
		if line, ierr := idna.ToASCII(line); ierr == nil {
			out = append(out, line)
		}
	}
	return out, s.Err()
}

func sha1hex(buf []byte) string {
	h := sha1.New()
	h.Write(buf)
	return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ecs"
)

const ECS_POLL_INTERVAL = 1 * time.Second

type ecsInterface interface {
	DescribeServices(*ecs.DescribeServicesInput) (*ecs.DescribeServicesOutput, error)
	CreateCluster(*ecs.CreateClusterInput) (*ecs.CreateClusterOutput, error)
	RegisterTaskDefinition(*ecs.RegisterTaskDefinitionInput) (*ecs.RegisterTaskDefinitionOutput, error)
	UpdateService(*ecs.UpdateServiceInput) (*ecs.UpdateServiceOutput, error)
}

func UpdateContainerImages(defs []*ecs.ContainerDefinition, images map[string]string) error {
	for name, image := range images {
		var matched bool
		for idx, containerDef := range defs {
			if *containerDef.Name == name {
				matched = true

				wanted := parseDockerImageName(image)
				current := parseDockerImageName(*containerDef.Image)

				log.Println(wanted, current)

				if wanted.Image != "" {
					defs[idx].Image = aws.String(wanted.String())
				} else {
					current.Tag = wanted.Tag
					defs[idx].Image = aws.String(current.String())
				}
			}
		}
		if !matched {
			return fmt.Errorf("No defined container named %q", name)
		}
	}

	return nil
}

type dockerImageName struct {
	Image string
	Tag   string
}

func parseDockerImageName(image string) *dockerImageName {
	parts := strings.SplitN(image, ":", 2)
	if len(parts) == 1 {
		parts = append(parts, "latest")
	}

	return &dockerImageName{Image: parts[0], Tag: parts[1]}
}

func (d *dockerImageName) String() string {
	return fmt.Sprintf("%s:%s", d.Image, d.Tag)
}

func getService(svc ecsInterface, cluster, service string) (*ecs.Service, error) {
	resp, err := svc.DescribeServices(&ecs.DescribeServicesInput{
		Services: []*string{aws.String(service)},
		Cluster:  aws.String(cluster),
	})
	if err != nil {
		return nil, err
	}

	if len(resp.Failures) > 0 {
		return nil, errors.New(*resp.Failures[0].Reason)
	}

	if len(resp.Services) != 1 {
		return nil, errors.New("Multiple services with the same name.")
	}

	return resp.Services[0], nil
}

func PollUntilTaskDeployed(svc ecsInterface, cluster string, service string, task string, f func(e *ecs.ServiceEvent)) error {
	lastSeen := time.Now().Add(-1 * time.Minute)

	for {
		service, err := getService(svc, cluster, service)
		if err != nil {
			return err
		}

		for i := len(service.Events) - 1; i >= 0; i-- {
			event := service.Events[i]
			if event.CreatedAt.After(lastSeen) {
				f(event)
				lastSeen = *event.CreatedAt
			}
		}

		if len(service.Deployments) == 1 && *service.Deployments[0].TaskDefinition == task {
			return nil
		}

		time.Sleep(ECS_POLL_INTERVAL)
	}
}

func ExposedPorts(taskDef *ecs.TaskDefinition) map[string][]*ecs.PortMapping {
	mappings := map[string][]*ecs.PortMapping{}

	for _, container := range taskDef.ContainerDefinitions {
		for _, mapping := range container.PortMappings {
			if mapping.HostPort != nil {
				if values, exists := mappings[*container.Name]; exists {
					mappings[*container.Name] = append(values, mapping)
				} else {
					mappings[*container.Name] = []*ecs.PortMapping{mapping}
				}
			}
		}
	}

	return mappings
}
<commit_msg>Removed println that wasn't needed<commit_after>package api

import (
	"errors"
	"fmt"
	"strings"

	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ecs"
)

const ECS_POLL_INTERVAL = 1 * time.Second

type ecsInterface interface {
	DescribeServices(*ecs.DescribeServicesInput) (*ecs.DescribeServicesOutput, error)
	CreateCluster(*ecs.CreateClusterInput) (*ecs.CreateClusterOutput, error)
	RegisterTaskDefinition(*ecs.RegisterTaskDefinitionInput) (*ecs.RegisterTaskDefinitionOutput, error)
	UpdateService(*ecs.UpdateServiceInput) (*ecs.UpdateServiceOutput, error)
}

func UpdateContainerImages(defs []*ecs.ContainerDefinition, images map[string]string) error {
	for name, image := range images {
		var matched bool
		for idx, containerDef := range defs {
			if *containerDef.Name == name {
				matched = true

				wanted := parseDockerImageName(image)
				current := parseDockerImageName(*containerDef.Image)

				if wanted.Image != "" {
					defs[idx].Image = aws.String(wanted.String())
				} else {
					current.Tag = wanted.Tag
					defs[idx].Image = aws.String(current.String())
				}
			}
		}
		if !matched {
			return fmt.Errorf("No defined container named %q", name)
		}
	}

	return nil
}

type dockerImageName struct {
	Image string
	Tag   string
}

func parseDockerImageName(image string) *dockerImageName {
	parts := strings.SplitN(image, ":", 2)
	if len(parts) == 1 {
		parts = append(parts, "latest")
	}

	return &dockerImageName{Image: parts[0], Tag: parts[1]}
}

func (d *dockerImageName) String() string {
	return fmt.Sprintf("%s:%s", d.Image, d.Tag)
}

func getService(svc ecsInterface, cluster, service string) (*ecs.Service, error) {
	resp, err := svc.DescribeServices(&ecs.DescribeServicesInput{
		Services: []*string{aws.String(service)},
		Cluster:  aws.String(cluster),
	})
	if err != nil {
		return nil, err
	}

	if len(resp.Failures) > 0 {
		return nil, errors.New(*resp.Failures[0].Reason)
	}

	if len(resp.Services) != 1 {
		return nil, errors.New("Multiple services with the same name.")
	}

	return resp.Services[0], nil
}

func PollUntilTaskDeployed(svc ecsInterface, cluster string, service string, task string, f func(e *ecs.ServiceEvent)) error {
	lastSeen := time.Now().Add(-1 * time.Minute)

	for {
		service, err := getService(svc, cluster, service)
		if err != nil {
			return err
		}

		for i := len(service.Events) - 1; i >= 0; i-- {
			event := service.Events[i]
			if event.CreatedAt.After(lastSeen) {
				f(event)
				lastSeen = *event.CreatedAt
			}
		}

		if len(service.Deployments) == 1 && *service.Deployments[0].TaskDefinition == task {
			return nil
		}

		time.Sleep(ECS_POLL_INTERVAL)
	}
}

func ExposedPorts(taskDef *ecs.TaskDefinition) map[string][]*ecs.PortMapping {
	mappings := map[string][]*ecs.PortMapping{}

	for _, container := range taskDef.ContainerDefinitions {
		for _, mapping := range container.PortMappings {
			if mapping.HostPort != nil {
				if values, exists := mappings[*container.Name]; exists {
					mappings[*container.Name] = append(values, mapping)
				} else {
					mappings[*container.Name] = []*ecs.PortMapping{mapping}
				}
			}
		}
	}

	return mappings
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/organisations-rw-neo4j/organisations"
	log "github.com/Sirupsen/logrus"
	"github.com/jawher/mow.cli"
)

func main() {
	app := cli.App("organisations-rw-neo4j", "A RESTful API for managing Organisations in neo4j")
	neoURL := app.String(cli.StringOpt{
		Name:   "neo-url",
		Value:  "http://localhost:7474/db/data",
		Desc:   "neo4j endpoint URL",
		EnvVar: "NEO_URL",
	})
	graphiteTCPAddress := app.String(cli.StringOpt{
		Name:   "graphiteTCPAddress",
		Value:  "",
		Desc:   "Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally",
		EnvVar: "GRAPHITE_ADDRESS",
	})
	graphitePrefix := app.String(cli.StringOpt{
		Name:   "graphitePrefix",
		Value:  "",
		Desc:   "Prefix to use. Should start with content, include the environment, and the host name. e.g. coco.pre-prod.roles-rw-neo4j.1 or content.test.people.rw.neo4j.ftaps58938-law1a-eu-t",
		EnvVar: "GRAPHITE_PREFIX",
	})
	port := app.Int(cli.IntOpt{
		Name:   "port",
		Value:  8080,
		Desc:   "Port to listen on",
		EnvVar: "APP_PORT",
	})
	batchSize := app.Int(cli.IntOpt{
		Name:   "batchSize",
		Value:  1024,
		Desc:   "Maximum number of statements to execute per batch",
		EnvVar: "BATCH_SIZE",
	})
	logMetrics := app.Bool(cli.BoolOpt{
		Name:   "logMetrics",
		Value:  false,
		Desc:   "Whether to log metrics. Set to true if running locally and you want metrics output",
		EnvVar: "LOG_METRICS",
	})
	env := app.String(cli.StringOpt{
		Name:  "env",
		Value: "local",
		Desc:  "environment this app is running in",
	})

	app.Action = func() {
		conf := neoutils.DefaultConnectionConfig()
		conf.BatchSize = *batchSize
		db, err := neoutils.Connect(*neoURL, conf)
		if err != nil {
			log.Errorf("Could not connect to neo4j, error=[%s]\n", err)
		}
		organisationsDriver := organisations.NewCypherOrganisationService(db)
		organisationsDriver.Initialise()

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)

		services := map[string]baseftrwapp.Service{
			"organisations": organisationsDriver,
		}

		var checks []v1a.Check
		for _, service := range services {
			checks = append(checks, makeCheck(service, db))
		}

		healthHandler := v1a.Handler("ft-organisations_rw_neo4j ServiceModule", "Writes 'organisations' to Neo4j, usually as part of a bulk upload done on a schedule", checks...)
		baseftrwapp.RunServerWithConf(baseftrwapp.RWConf{
			Services:      services,
			HealthHandler: healthHandler,
			Port:          *port,
			ServiceName:   "organisations-rw-neo4j",
			Env:           *env,
			EnableReqLog:  false,
		})
	}
	log.SetLevel(log.InfoLevel)
	log.Println("Application started with args %s", os.Args)

	app.Run(os.Args)
}

func makeCheck(service baseftrwapp.Service, cr neoutils.CypherRunner) v1a.Check {
	return v1a.Check{
		BusinessImpact:   "Cannot read/write organisations via this writer",
		Name:             "Check connectivity to Neo4j - neoUrl is a parameter in hieradata for this service",
		PanicGuide:       "TODO - write panic guide",
		Severity:         1,
		TechnicalSummary: fmt.Sprintf("Cannot connect to Neo4j instance %s with at least one organisation loaded in it", cr),
		Checker: func() (string, error) {
			return "", service.Check()
		},
	}
}
<commit_msg>fixed Application starting with args %s<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/organisations-rw-neo4j/organisations"
	log "github.com/Sirupsen/logrus"
	"github.com/jawher/mow.cli"
)

func main() {
	app := cli.App("organisations-rw-neo4j", "A RESTful API for managing Organisations in neo4j")
	neoURL := app.String(cli.StringOpt{
		Name:   "neo-url",
		Value:  "http://localhost:7474/db/data",
		Desc:   "neo4j endpoint URL",
		EnvVar: "NEO_URL",
	})
	graphiteTCPAddress := app.String(cli.StringOpt{
		Name:   "graphiteTCPAddress",
		Value:  "",
		Desc:   "Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally",
		EnvVar: "GRAPHITE_ADDRESS",
	})
	graphitePrefix := app.String(cli.StringOpt{
		Name:   "graphitePrefix",
		Value:  "",
		Desc:   "Prefix to use. Should start with content, include the environment, and the host name. e.g. coco.pre-prod.roles-rw-neo4j.1 or content.test.people.rw.neo4j.ftaps58938-law1a-eu-t",
		EnvVar: "GRAPHITE_PREFIX",
	})
	port := app.Int(cli.IntOpt{
		Name:   "port",
		Value:  8080,
		Desc:   "Port to listen on",
		EnvVar: "APP_PORT",
	})
	batchSize := app.Int(cli.IntOpt{
		Name:   "batchSize",
		Value:  1024,
		Desc:   "Maximum number of statements to execute per batch",
		EnvVar: "BATCH_SIZE",
	})
	logMetrics := app.Bool(cli.BoolOpt{
		Name:   "logMetrics",
		Value:  false,
		Desc:   "Whether to log metrics. Set to true if running locally and you want metrics output",
		EnvVar: "LOG_METRICS",
	})
	env := app.String(cli.StringOpt{
		Name:  "env",
		Value: "local",
		Desc:  "environment this app is running in",
	})

	app.Action = func() {
		conf := neoutils.DefaultConnectionConfig()
		conf.BatchSize = *batchSize
		db, err := neoutils.Connect(*neoURL, conf)
		if err != nil {
			log.Errorf("Could not connect to neo4j, error=[%s]\n", err)
		}
		organisationsDriver := organisations.NewCypherOrganisationService(db)
		organisationsDriver.Initialise()

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)

		services := map[string]baseftrwapp.Service{
			"organisations": organisationsDriver,
		}

		var checks []v1a.Check
		for _, service := range services {
			checks = append(checks, makeCheck(service, db))
		}

		healthHandler := v1a.Handler("ft-organisations_rw_neo4j ServiceModule", "Writes 'organisations' to Neo4j, usually as part of a bulk upload done on a schedule", checks...)
		baseftrwapp.RunServerWithConf(baseftrwapp.RWConf{
			Services:      services,
			HealthHandler: healthHandler,
			Port:          *port,
			ServiceName:   "organisations-rw-neo4j",
			Env:           *env,
			EnableReqLog:  false,
		})
	}
	log.SetLevel(log.InfoLevel)
	log.Printf("Application started with args %v", os.Args)

	app.Run(os.Args)
}

func makeCheck(service baseftrwapp.Service, cr neoutils.CypherRunner) v1a.Check {
	return v1a.Check{
		BusinessImpact:   "Cannot read/write organisations via this writer",
		Name:             "Check connectivity to Neo4j - neoUrl is a parameter in hieradata for this service",
		PanicGuide:       "TODO - write panic guide",
		Severity:         1,
		TechnicalSummary: fmt.Sprintf("Cannot connect to Neo4j instance %s with at least one organisation loaded in it", cr),
		Checker: func() (string, error) {
			return "", service.Check()
		},
	}
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"

	"github.com/hoffie/larasync/helpers/bincontainer"
	repositoryModule "github.com/hoffie/larasync/repository"
)

// nibGet returns the NIB data for a given repository and a given UUID.
func (s *Server) nibGet(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorJSON(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	nibID := vars["nibID"]

	reader, err := repository.GetNIBReader(nibID)

	if err != nil {
		rw.Header().Set("Content-Type", "plain/text")
		if os.IsNotExist(err) {
			errorText(rw, "Not found", http.StatusNotFound)
		} else {
			errorText(rw, "Internal Error", http.StatusInternalServerError)
		}
		return
	}

	defer reader.Close()

	rw.Header().Set("Content-Type", "application/octet-stream")
	attachCurrentTransactionHeader(repository, rw)
	rw.WriteHeader(http.StatusOK)
	io.Copy(rw, reader)
}

// nibPut is the handler which adds a NIB to the repository.
func (s *Server) nibPut(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorJSON(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	nibID := vars["nibID"]

	successReturnStatus := http.StatusOK
	if !repository.HasNIB(nibID) {
		successReturnStatus = http.StatusCreated
	}

	err = repository.AddNIBContent(req.Body)

	if err != nil {
		if err == repositoryModule.ErrSignatureVerification {
			errorText(rw, "Signature could not be verified", http.StatusUnauthorized)
		} else if err == repositoryModule.ErrUnMarshalling {
			errorText(rw, "Could not extract NIB", http.StatusBadRequest)
		} else if err == repositoryModule.ErrNIBConflict {
			errorText(rw, "NIB conflict", http.StatusConflict)
		} else if repositoryModule.IsNIBContentMissing(err) {
			errorText(rw, err.Error(), http.StatusPreconditionFailed)
		} else {
			errorText(rw, "Internal Error", http.StatusInternalServerError)
		}
		return
	}

	rw.Header().Set("Location", req.URL.String())
	attachCurrentTransactionHeader(repository, rw)
	rw.WriteHeader(successReturnStatus)
}

func (s *Server) nibList(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorText(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	values := req.URL.Query()
	fromRepositoryIDString, ok := values["from-transaction-id"]

	var nibChannel <-chan []byte
	if !ok {
		nibChannel, err = repository.GetAllNIBBytes()
	} else {
		fromRepositoryID, err := strconv.ParseInt(fromRepositoryIDString[0], 10, 64)
		if err != nil {
			errorText(
				rw,
				fmt.Sprintf(
					"from-transaction-id %s is not a valid transaction id",
					fromRepositoryIDString,
				),
				http.StatusBadRequest,
			)
			return
		}
		nibChannel, err = repository.GetNIBBytesFrom(fromRepositoryID)
	}

	if err != nil {
		errorText(rw, "Could not extract data", http.StatusInternalServerError)
		return
	}

	header := rw.Header()
	header.Set("Content-Type", "application/octet-stream")
	attachCurrentTransactionHeader(repository, rw)

	rw.WriteHeader(http.StatusOK)

	encoder := bincontainer.NewEncoder(rw)
	for nibData := range nibChannel {
		encoder.WriteChunk(nibData)
	}
}
<commit_msg>api: reformat unclear else<commit_after>package api

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"

	"github.com/hoffie/larasync/helpers/bincontainer"
	repositoryModule "github.com/hoffie/larasync/repository"
)

// nibGet returns the NIB data for a given repository and a given UUID.
func (s *Server) nibGet(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorJSON(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	nibID := vars["nibID"]

	reader, err := repository.GetNIBReader(nibID)

	if err != nil {
		rw.Header().Set("Content-Type", "plain/text")
		if os.IsNotExist(err) {
			errorText(rw, "Not found", http.StatusNotFound)
		} else {
			errorText(rw, "Internal Error", http.StatusInternalServerError)
		}
		return
	}

	defer reader.Close()

	rw.Header().Set("Content-Type", "application/octet-stream")
	attachCurrentTransactionHeader(repository, rw)
	rw.WriteHeader(http.StatusOK)
	io.Copy(rw, reader)
}

// nibPut is the handler which adds a NIB to the repository.
func (s *Server) nibPut(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorJSON(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	nibID := vars["nibID"]

	successReturnStatus := http.StatusOK
	if !repository.HasNIB(nibID) {
		successReturnStatus = http.StatusCreated
	}

	err = repository.AddNIBContent(req.Body)

	if err != nil {
		if err == repositoryModule.ErrSignatureVerification {
			errorText(rw, "Signature could not be verified", http.StatusUnauthorized)
		} else if err == repositoryModule.ErrUnMarshalling {
			errorText(rw, "Could not extract NIB", http.StatusBadRequest)
		} else if err == repositoryModule.ErrNIBConflict {
			errorText(rw, "NIB conflict", http.StatusConflict)
		} else if repositoryModule.IsNIBContentMissing(err) {
			errorText(rw, err.Error(), http.StatusPreconditionFailed)
		}
		errorText(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	rw.Header().Set("Location", req.URL.String())
	attachCurrentTransactionHeader(repository, rw)
	rw.WriteHeader(successReturnStatus)
}

func (s *Server) nibList(rw http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	repositoryName := vars["repository"]

	repository, err := s.rm.Open(repositoryName)
	if err != nil {
		errorText(rw, "Internal Error", http.StatusInternalServerError)
		return
	}

	values := req.URL.Query()
	fromRepositoryIDString, ok := values["from-transaction-id"]

	var nibChannel <-chan []byte
	if !ok {
		nibChannel, err = repository.GetAllNIBBytes()
	} else {
		fromRepositoryID, err := strconv.ParseInt(fromRepositoryIDString[0], 10, 64)
		if err != nil {
			errorText(
				rw,
				fmt.Sprintf(
					"from-transaction-id %s is not a valid transaction id",
					fromRepositoryIDString,
				),
				http.StatusBadRequest,
			)
			return
		}
		nibChannel, err = repository.GetNIBBytesFrom(fromRepositoryID)
	}

	if err != nil {
		errorText(rw, "Could not extract data", http.StatusInternalServerError)
		return
	}

	header := rw.Header()
	header.Set("Content-Type", "application/octet-stream")
	attachCurrentTransactionHeader(repository, rw)

	rw.WriteHeader(http.StatusOK)

	encoder := bincontainer.NewEncoder(rw)
	for nibData := range nibChannel {
		encoder.WriteChunk(nibData)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof" // import for side effects
	"os"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/justinas/alice"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/hello/{name}", helloHandler)

	// add middleware
	stderrLoggingHandler := func(http.Handler) http.Handler {
		return handlers.LoggingHandler(os.Stderr, r)
	}
	middlewareRouter := alice.New(handlers.CompressHandler, stderrLoggingHandler).Then(r)

	// serve http
	http.Handle("/", middlewareRouter)
	http.ListenAndServe(":8080", nil)

	http.HandleFunc("/health", healthHandler)
	http.ListenAndServe(":8080", nil)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	args := mux.Vars(r)
	fmt.Fprintf(w, "Hello %s!", args["name"])
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("healthy!"))
}
<commit_msg>Revert "Health endpoint"<commit_after>package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof" // import for side effects
	"os"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/justinas/alice"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/hello/{name}", helloHandler)

	// add middleware
	stderrLoggingHandler := func(http.Handler) http.Handler {
		return handlers.LoggingHandler(os.Stderr, r)
	}
	middlewareRouter := alice.New(handlers.CompressHandler, stderrLoggingHandler).Then(r)

	// serve http
	http.Handle("/", middlewareRouter)
	http.ListenAndServe(":8080", nil)
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	args := mux.Vars(r)
	fmt.Fprintf(w, "Hello %s!", args["name"])
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type method struct {
	params []interface{}
}

var parsed map[string]map[string]method

var suggested = [...]string{
	"io.ByteReader",
	"io.ByteScanner",
	"io.ByteWriter",
	"io.Closer",
	"io.ReadCloser",
	"io.ReadSeeker",
	"io.ReadWriteCloser",
	"io.ReadWriteSeeker",
	"io.ReadWriter",
	"io.Reader",
	"io.ReaderAt",
	"io.ReaderFrom",
	"io.RuneReader",
	"io.RuneScanner",
	"io.Seeker",
	"io.WriteCloser",
	"io.WriteSeeker",
	"io.Writer",
	"io.WriterAt",
	"io.WriterTo",
}

func typeList(t *types.Tuple) []interface{} {
	var l []interface{}
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		l = append(l, v.Type())
	}
	return l
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]method, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		if _, e := parsed[ifname]; e {
			log.Fatalf("%s is duplicated", ifname)
		}
		parsed[ifname] = make(map[string]method, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			parsed[ifname][fname] = method{
				params: typeList(sign.Params()),
			}
		}
	}
}

func init() {
	typesInit()
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	case nil:
		switch t1.(type) {
		case *types.Slice:
			return true
		case *types.Map:
			return true
		default:
			return false
		}
	default:
		return false
	}
}

func typesMatch(args1, args2 []interface{}) bool {
	if len(args1) != len(args2) {
		return false
	}
	for i, a1 := range args1 {
		a2 := args2[i]
		t1 := a1.(types.Type)
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(methods map[string]method) string {
	matchesIface := func(decls map[string]method) bool {
		if len(methods) > len(decls) {
			return false
		}
		for n, d := range decls {
			m, e := methods[n]
			if !e {
				return false
			}
			if !typesMatch(d.params, m.params) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	params map[string]types.Type
	used   map[string]map[string]method
}

func scopeName(e ast.Expr) string {
	switch x := e.(type) {
	case *ast.Ident:
		return x.Name
	case *ast.StarExpr:
		return scopeName(x.X)
	default:
		return ""
	}
}

func (v *Visitor) getFuncType(fd *ast.FuncDecl) *types.Func {
	name := fd.Name.Name
	scope := v.scopes[len(v.scopes)-1]
	if fd.Recv == nil {
		return scope.Lookup(name).(*types.Func)
	}
	if len(fd.Recv.List) > 1 {
		return nil
	}
	tname := scopeName(fd.Recv.List[0].Type)
	st := scope.Lookup(tname).(*types.TypeName)
	named := st.Type().(*types.Named)
	for i := 0; i < named.NumMethods(); i++ {
		f := named.Method(i)
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.getFuncType(x)
		if f == nil {
			return nil
		}
		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.used = make(map[string]map[string]method, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.params[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.params = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := method{}
	for _, a := range c.Args {
		m.params = append(m.params, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]method)
	}
	v.used[vname][fname] = m
}
<commit_msg>Make function declarations more specific<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type funcDecl struct {
	params []types.Type
}

var parsed map[string]map[string]funcDecl

var suggested = [...]string{
	"io.ByteReader",
	"io.ByteScanner",
	"io.ByteWriter",
	"io.Closer",
	"io.ReadCloser",
	"io.ReadSeeker",
	"io.ReadWriteCloser",
	"io.ReadWriteSeeker",
	"io.ReadWriter",
	"io.Reader",
	"io.ReaderAt",
	"io.ReaderFrom",
	"io.RuneReader",
	"io.RuneScanner",
	"io.Seeker",
	"io.WriteCloser",
	"io.WriteSeeker",
	"io.Writer",
	"io.WriterAt",
	"io.WriterTo",
}

func typeList(t *types.Tuple) []types.Type {
	var l []types.Type
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		l = append(l, v.Type())
	}
	return l
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]funcDecl, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		if _, e := parsed[ifname]; e {
			log.Fatalf("%s is duplicated", ifname)
		}
		parsed[ifname] = make(map[string]funcDecl, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			parsed[ifname][fname] = funcDecl{
				params: typeList(sign.Params()),
			}
		}
	}
}

func init() {
	typesInit()
}

type call struct {
	params []interface{}
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	case nil:
		switch t1.(type) {
		case *types.Slice:
			return true
		case *types.Map:
			return true
		default:
			return false
		}
	default:
		return false
	}
}

func typesMatch(types1 []types.Type, args2 []interface{}) bool {
	if len(types1) != len(args2) {
		return false
	}
	for i, t1 := range types1 {
		a2 := args2[i]
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(calls map[string]call) string {
	matchesIface := func(decls map[string]funcDecl) bool {
		if len(calls) > len(decls) {
			return false
		}
		for n, d := range decls {
			c, e := calls[n]
			if !e {
				return false
			}
			if !typesMatch(d.params, c.params) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	params map[string]types.Type
	used   map[string]map[string]call
}

func scopeName(e ast.Expr) string {
	switch x := e.(type) {
	case *ast.Ident:
		return x.Name
	case *ast.StarExpr:
		return scopeName(x.X)
	default:
		return ""
	}
}

func (v *Visitor) getFuncType(fd *ast.FuncDecl) *types.Func {
	name := fd.Name.Name
	scope := v.scopes[len(v.scopes)-1]
	if fd.Recv == nil {
		return scope.Lookup(name).(*types.Func)
	}
	if len(fd.Recv.List) > 1 {
		return nil
	}
	tname := scopeName(fd.Recv.List[0].Type)
	st := scope.Lookup(tname).(*types.TypeName)
	named := st.Type().(*types.Named)
	for i := 0; i < named.NumMethods(); i++ {
		f := named.Method(i)
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.getFuncType(x)
		if f == nil {
			return nil
		}
		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.used = make(map[string]map[string]call, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.params[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.params = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := call{}
	for _, a := range c.Args {
		m.params = append(m.params, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]call)
	}
	v.used[vname][fname] = m
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"net/http"
	"github.com/gorilla/mux"
)

func main() {
	apiRouter := mux.NewRouter().
		StrictSlash(false)

	initBusinessRouter(apiRouter)

	http.ListenAndServe(":8000", apiRouter)
}

func initBusinessRouter(parent *mux.Router) {
	businessRouter := parent.PathPrefix("/api/business").
		Subrouter()
	businessRouter.HandleFunc("/login/", businessLoginHandler)
	businessRouter.HandleFunc("/register/", businessRegistrationHandler)

}

func decodeJSON(src io.Reader, dst interface{}) error {
	decoder := json.NewDecoder(src)
	err := decoder.Decode(dst)
	return err
}
<commit_msg>Add encodeJSON func<commit_after>package main

import (
	"encoding/json"
	"io"
	"net/http"

	"github.com/gorilla/mux"
)

func main() {
	apiRouter := mux.NewRouter().
		StrictSlash(false)

	initBusinessRouter(apiRouter)

	http.ListenAndServe(":8000", apiRouter)
}

func initBusinessRouter(parent *mux.Router) {
	businessRouter := parent.PathPrefix("/api/business").
		Subrouter()
	businessRouter.HandleFunc("/login/", businessLoginHandler)
	businessRouter.HandleFunc("/register/", businessRegistrationHandler)

}

func decodeJSON(src io.Reader, dst interface{}) error {
	decoder := json.NewDecoder(src)
	err := decoder.Decode(dst)
	return err
}

func encodeJSON(dst io.Writer, src interface{}) error {
	encoder := json.NewEncoder(dst)
	err := encoder.Encode(src)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	log "github.com/Sirupsen/logrus"

	"github.com/rancher/websocket-proxy/proxy"
)

func main() {

	conf, err := proxy.GetConfig()
	if err != nil {
		log.WithField("error", err).Fatal("Error getting config.")
	}

	p := &proxy.Starter{
		BackendPaths: []string{
			"/v1/connectbackend",
			"/v2-beta/connectbackend",
		},
		FrontendPaths: []string{
			"/v1/{logs:logs}",
			"/v1/{logs:logs}/",
			"/v1/{stats:stats}",
			"/v1/{stats:stats}/{statsid}",
			"/v1/exec/",
			"/v1/exec",
			"/v1/console/",
			"/v1/console",
			"/v1/dockersocket/",
			"/v1/dockersocket",
			"/v2-beta/{logs:logs}/",
			"/v2-beta/{logs:logs}",
			"/v2-beta/{stats:stats}",
			"/v2-beta/{stats:stats}/{statsid}",
			"/v2-beta/exec/",
			"/v2-beta/exec",
			"/v2-beta/console/",
			"/v2-beta/console",
			"/v2-beta/dockersocket/",
			"/v2-beta/dockersocket",
		},
		FrontendHTTPPaths: []string{
			"/v1/container-proxy{path:.*}",
			"/v2-beta/container-proxy{path:.*}",
			"/r/projects/{project}/{service}{path:.*}",
			"/r/{service}{path:.*}",
		},
		StatsPaths: []string{
			"/v1/{hoststats:hoststats(\\/project)?(\\/)?}",
			"/v1/{containerstats:containerstats(\\/service)?(\\/)?}",
			"/v1/{containerstats:containerstats}/{containerid}",
			"/v2-beta/{hoststats:hoststats(\\/project)?(\\/)?}",
			"/v2-beta/{containerstats:containerstats(\\/service)?(\\/)?}",
			"/v2-beta/{containerstats:containerstats}/{containerid}",
		},
		CattleWSProxyPaths: []string{
			"/v1/{sub:subscribe}",
			"/v1/projects/{project}/{sub:subscribe}",
			"/v2-beta/{sub:subscribe}",
			"/v2-beta/projects/{project}/{sub:subscribe}",
		},
		CattleProxyPaths: []string{
			"/{cattle-proxy:.*}",
		},
		Config: conf,
	}

	log.Infof("Starting websocket proxy. Listening on [%s], Proxying to cattle API at [%s], Monitoring parent pid [%v].",
		conf.ListenAddr, conf.CattleAddr, conf.ParentPid)

	err = p.StartProxy()

	log.WithFields(log.Fields{"error": err}).Info("Exiting proxy.")
}
<commit_msg>Add v2 routes<commit_after>package main

import (
	log "github.com/Sirupsen/logrus"

	"github.com/rancher/websocket-proxy/proxy"
)

func main() {

	conf, err := proxy.GetConfig()
	if err != nil {
		log.WithField("error", err).Fatal("Error getting config.")
	}

	p := &proxy.Starter{
		BackendPaths: []string{
			"/v1/connectbackend",
			"/v2-beta/connectbackend",
			"/v2/connectbackend",
		},
		FrontendPaths: []string{
			"/v1/{logs:logs}",
			"/v1/{logs:logs}/",
			"/v1/{stats:stats}",
			"/v1/{stats:stats}/{statsid}",
			"/v1/exec/",
			"/v1/exec",
			"/v1/console/",
			"/v1/console",
			"/v1/dockersocket/",
			"/v1/dockersocket",
			"/v2-beta/{logs:logs}/",
			"/v2-beta/{logs:logs}",
			"/v2-beta/{stats:stats}",
			"/v2-beta/{stats:stats}/{statsid}",
			"/v2-beta/exec/",
			"/v2-beta/exec",
			"/v2-beta/console/",
			"/v2-beta/console",
			"/v2-beta/dockersocket/",
			"/v2-beta/dockersocket",
			"/v2/{logs:logs}/",
			"/v2/{logs:logs}",
			"/v2/{stats:stats}",
			"/v2/{stats:stats}/{statsid}",
			"/v2/exec/",
			"/v2/exec",
			"/v2/console/",
			"/v2/console",
			"/v2/dockersocket/",
			"/v2/dockersocket",
		},
		FrontendHTTPPaths: []string{
			"/v1/container-proxy{path:.*}",
			"/v2-beta/container-proxy{path:.*}",
			"/v2/container-proxy{path:.*}",
			"/r/projects/{project}/{service}{path:.*}",
			"/r/{service}{path:.*}",
		},
		StatsPaths: []string{
			"/v1/{hoststats:hoststats(\\/project)?(\\/)?}",
			"/v1/{containerstats:containerstats(\\/service)?(\\/)?}",
			"/v1/{containerstats:containerstats}/{containerid}",
			"/v2-beta/{hoststats:hoststats(\\/project)?(\\/)?}",
			"/v2-beta/{containerstats:containerstats(\\/service)?(\\/)?}",
			"/v2-beta/{containerstats:containerstats}/{containerid}",
			"/v2/{hoststats:hoststats(\\/project)?(\\/)?}",
			"/v2/{containerstats:containerstats(\\/service)?(\\/)?}",
			"/v2/{containerstats:containerstats}/{containerid}",
		},
		CattleWSProxyPaths: []string{
			"/v1/{sub:subscribe}",
			"/v1/projects/{project}/{sub:subscribe}",
			"/v2-beta/{sub:subscribe}",
			"/v2-beta/projects/{project}/{sub:subscribe}",
			"/v2/{sub:subscribe}",
			"/v2/projects/{project}/{sub:subscribe}",
		},
		CattleProxyPaths: []string{
			"/{cattle-proxy:.*}",
		},
		Config: conf,
	}

	log.Infof("Starting websocket proxy. Listening on [%s], Proxying to cattle API at [%s], Monitoring parent pid [%v].",
		conf.ListenAddr, conf.CattleAddr, conf.ParentPid)

	err = p.StartProxy()

	log.WithFields(log.Fields{"error": err}).Info("Exiting proxy.")
}
<|endoftext|>


<commit_before><commit_msg>main: reorganize workarea lookup and default 'hwaf' command handling<commit_after><|endoftext|>


<commit_before><commit_msg>Extract parseFlags<commit_after><|endoftext|>


<commit_before><commit_msg>nit(ui) probably more helpful to have the PGID than just the fact of failure<commit_after><|endoftext|>


<commit_before><commit_msg>Show what app version was found<commit_after><|endoftext|>


<commit_before><commit_msg>fix virtual entry<commit_after><|endoftext|>


<commit_before><commit_msg>split rwc<commit_after><|endoftext|>


<commit_before><commit_msg>Fix issue with auth backend being recreated on reruns.<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed a few bugs in MirrorBandStats<commit_after><|endoftext|>


<commit_before><commit_msg>Menu redesign<commit_after><|endoftext|>


<commit_before><commit_msg>Minor edits<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var (
	dumpBoltDescription = `Dumps a bolt database. The output format should not be depended upon.`
	dumpBoltCommand     = &cobra.Command{
		Use:     "dumpbolt",
		Short:   "Dump a bolt database",
		Long:    dumpBoltDescription,
		RunE:    dumpBoltCmd,
		Example: "DATABASE",
		Args:    cobra.ExactArgs(1),
		Hidden:  true,
	}
)

func dumpBoltCmd(c *cobra.Command, args []string) error {
	db, err := bolt.Open(args[0], 0600, &bolt.Options{ReadOnly: true})
	if err != nil {
		return errors.Wrapf(err, "error opening database %q", args[0])
	}
	defer db.Close()

	encode := func(value []byte) string {
		var b strings.Builder
		for i := range value {
			if value[i] <= 32 || value[i] >= 127 || value[i] == 34 || value[i] == 61 {
				b.WriteString(fmt.Sprintf("\\%03o", value[i]))
			} else {
				b.WriteByte(value[i])
			}
		}
		return b.String()
	}

	return db.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			fmt.Printf("[%q]\n", encode(name))
			return b.ForEach(func(k, v []byte) (err error) {
				_, err = fmt.Printf(" %q = %q\n", encode(k), encode(v))
				return err
			})
		})
	})
}

func init() {
	rootCmd.AddCommand(dumpBoltCommand)
}
<commit_msg>dumpbolt: handle nested buckets<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var (
	dumpBoltDescription = `Dumps a bolt database. The output format should not be depended upon.`
	dumpBoltCommand     = &cobra.Command{
		Use:     "dumpbolt",
		Short:   "Dump a bolt database",
		Long:    dumpBoltDescription,
		RunE:    dumpBoltCmd,
		Example: "DATABASE",
		Args:    cobra.ExactArgs(1),
		Hidden:  true,
	}
)

func dumpBoltCmd(c *cobra.Command, args []string) error {
	db, err := bolt.Open(args[0], 0600, &bolt.Options{ReadOnly: true})
	if err != nil {
		return errors.Wrapf(err, "error opening database %q", args[0])
	}
	defer db.Close()

	encode := func(value []byte) string {
		var b strings.Builder
		for i := range value {
			if value[i] <= 32 || value[i] >= 127 {
				b.WriteString(fmt.Sprintf("\\%03o", value[i]))
			} else {
				b.WriteByte(value[i])
			}
		}
		return b.String()
	}

	return db.View(func(tx *bolt.Tx) error {
		var dumpBucket func(string, []byte, *bolt.Bucket) error
		dumpBucket = func(indent string, name []byte, b *bolt.Bucket) error {
			var subs [][]byte
			indentMore := "  "
			fmt.Printf("%s%s:\n", indent, encode(name))
			err := b.ForEach(func(k, v []byte) (err error) {
				if v == nil {
					subs = append(subs, k)
				} else {
					_, err = fmt.Printf("%s%s: %s\n", indent+indentMore, encode(k), encode(v))
				}
				return err
			})
			if err != nil {
				return err
			}
			for _, sub := range subs {
				subbucket := b.Bucket(sub)
				if err = dumpBucket(indent+indentMore, sub, subbucket); err != nil {
					return err
				}
			}
			return err
		}
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error { return dumpBucket("", name, b) })
	})
}

func init() {
	rootCmd.AddCommand(dumpBoltCommand)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.tools/go/types"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
)

var (
	universe string
	own      string
)

func init() {
	flag.StringVar(&universe, "universe", "std", "Comma-separated list of Which packages to scan for interfaces. Defaults to std.")
	flag.StringVar(&own, "own", "", "Comma-separated list of packages whose types to check for implemented interfaces.")

	flag.Parse()
}

type Interface struct {
	Name       string
	Underlying *types.Interface
	Obj        types.Object
}

// getInterfaces extracts all the interfaces from the objects we
// parsed.
func getInterfaces(typs []types.Object) []Interface {
	var interfaces []Interface

	for _, obj := range typs {
		// Only types, not variables/constants
		if v, ok := obj.(*types.TypeName); ok {
			// Only interfaces
			if iface, ok := v.Type().Underlying().(*types.Interface); ok {
				interfaces = append(interfaces, Interface{obj.Name(), iface, obj})
			}
		}

	}

	return interfaces
}

func parseFile(fset *token.FileSet, fileName string) (f *ast.File, err error) {
	astFile, err := parser.ParseFile(fset, fileName, nil, 0)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	return astFile, nil
}

type Context struct {
	allImports map[string]*types.Package
	context    types.Context
}

func NewContext() *Context {
	ctx := &Context{
		allImports: make(map[string]*types.Package),
	}

	ctx.context = types.Context{
		Import: ctx.importer,
	}

	return ctx
}

func (ctx *Context) importer(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
	// types.Importer does not seem to be designed for recursive
	// parsing like we're doing here. Specifically, each nested import
	// will maintain its own imports map. This will lead to duplicate
	// imports and in turn packages, which will lead to funny errors
	// such as "cannot pass argument ip (variable of type net.IP) to
	// variable of type net.IP"
	//
	// To work around this, we keep a global imports map, allImports,
	// to which we add all nested imports, and which we use as the
	// cache, instead of imports.
	//
	// Since all nested imports will also use this importer, there
	// should be no way to end up with duplicate imports.

	// We first try to use GcImport directly. This has the downside of
	// using possibly out-of-date packages, but it has the upside of
	// not having to parse most of the Go standard library.

	buildPkg, buildErr := build.Import(path, ".", 0)
	// If we found no build dir, assume we're dealing with installed
	// but no source. If we found a build dir, only use GcImport if
	// it's in GOROOT. This way we always use up-to-date code for
	// normal packages but avoid parsing the standard library.
	if (buildErr == nil && buildPkg.Goroot) || buildErr != nil {
		pkg, err = types.GcImport(ctx.allImports, path)
		if err == nil {
			// We don't use imports, but per API we have to add the package.
			imports[pkg.Path()] = pkg
			ctx.allImports[pkg.Path()] = pkg
			return pkg, nil
		}
	}

	// See if we already imported this package
	if pkg = ctx.allImports[path]; pkg != nil && pkg.Complete() {
		return pkg, nil
	}

	// allImports failed, try to use go/build
	if buildErr != nil {
		return nil, buildErr
	}

	// TODO check if the .a file is up to date and use it instead
	fmt.Println("we have to build", path, "ourselves")
	fileSet := token.NewFileSet()

	isGoFile := func(d os.FileInfo) bool {
		allFiles := make([]string, 0, len(buildPkg.GoFiles)+len(buildPkg.CgoFiles))
		allFiles = append(allFiles, buildPkg.GoFiles...)
		allFiles = append(allFiles, buildPkg.CgoFiles...)

		for _, file := range allFiles {
			if file == d.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, isGoFile, 0)
	if err != nil {
		return nil, err
	}

	delete(pkgs, "documentation")
	var astPkg *ast.Package
	var name string
	for name, astPkg = range pkgs {
		// Use the first non-main package, or the only package we
		// found.
		//
		// NOTE(dh) I can't think of a reason why there should be
		// multiple packages in a single directory, but ParseDir
		// accommodates for that possibility.
		if len(pkgs) == 1 || name != "main" {
			break
		}
	}

	if astPkg == nil {
		return nil, fmt.Errorf("can't find import: %s", name)
	}

	var ff []*ast.File
	for _, f := range astPkg.Files {
		ff = append(ff, f)
	}

	context := types.Context{
		Import: ctx.importer,
	}

	pkg, err = context.Check(name, fileSet, ff...)
	if err != nil {
		return pkg, err
	}
	if !pkg.Complete() {
		pkg = types.NewPackage(pkg.Pos(), pkg.Path(), pkg.Name(), pkg.Scope(), pkg.Imports(), true)
	}

	imports[path] = pkg
	ctx.allImports[path] = pkg
	return pkg, nil
}

func (ctx *Context) getTypes(paths ...string) []types.Object {
	var typs []types.Object

	for _, path := range paths {
		buildPkg, err := build.Import(path, ".", 0)
		if err != nil {
			// FIXME better error handling
			fmt.Printf("Couldn't import %s: %s\n", path, err)
			continue
		}
		fset := token.NewFileSet()
		var astFiles []*ast.File
		var pkg *types.Package
		if buildPkg.Goroot {
			// TODO what if the compiled package in GoRoot is
			// outdated?
			fmt.Println("GcImport", path)
			pkg, err = types.GcImport(ctx.allImports, path)
			if err != nil {
				// TODO better error handling
				fmt.Printf("Couldn't import %s: %s\n", path, err)
				continue
			}
		} else {
			fmt.Println("Manual parsing", path)
			if len(buildPkg.GoFiles) == 0 {
				// TODO proper error handling
				fmt.Printf("Couldn't parse %s: No go files\n", path)
				continue
			}
			for _, file := range buildPkg.GoFiles {
				astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file))
				if err != nil {
					// TODO proper error handling
					fmt.Printf("Couldn't parse %s: %s", err)
					continue
				}
				astFiles = append(astFiles, astFile)
			}

			pkg, err = check(ctx, astFiles[0].Name.Name, fset, astFiles)
			if err != nil {
				// FIXME better error handling
				fmt.Printf("Couldn't parse %s: %s\n", path, err)
				continue
			}
			fmt.Println(pkg.Name(), pkg.Complete())
		}

		scope := pkg.Scope()
		for i := 0; i < scope.NumEntries(); i++ {
			obj := scope.At(i)

			// Only types, not variables/constants
			if _, ok := obj.(*types.TypeName); ok {
				typs = append(typs, obj)
			}

		}
	}
	return typs
}

func check(ctx *Context, name string, fset *token.FileSet, astFiles []*ast.File) (pkg *types.Package, err error) {
	return ctx.context.Check(name, fset, astFiles...)
}

func main() {
	if own == "" {
		flag.Usage()
		os.Exit(1)
	}

	ctx := NewContext()
	stdlib := ctx.getTypes(matchPackages(universe)...)
	toCheck := ctx.getTypes(matchPackages(own)...)

	interfaces := getInterfaces(stdlib)

	for _, typ := range toCheck {
		for _, iface := range interfaces {
			if iface.Underlying.NumMethods() == 0 {
				continue
			}

			if typ.Object.Pkg() == iface.Obj.Pkg() && typ.Object.Name() == iface.Name {
				// An interface will always implement itself, so skip those
				continue
			}

			if fnc, _ := types.MissingMethod(typ.Type(), iface.Underlying); fnc == nil {
				fmt.Printf("%s.%s implements %s.%s\n",
					typ.(*types.TypeName).Pkg().Name(), typ.Name(),
					iface.Obj.Pkg().Name(), iface.Name)
			}
		}
	}
}
<commit_msg>also check pointer versions of types; group types in output<commit_after>package main

import (
	"code.google.com/p/go.tools/go/types"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
)

var (
	universe string
	own      string
)

func init() {
	flag.StringVar(&universe, "universe", "std", "Comma-separated list of Which packages to scan for interfaces. Defaults to std.")
	flag.StringVar(&own, "own", "", "Comma-separated list of packages whose types to check for implemented interfaces.")

	flag.Parse()
}

type Interface struct {
	Name       string
	Underlying *types.Interface
	Obj        types.Object
}

type Type struct {
	Object   types.Object
	TypeName *types.TypeName
	Pointer  *types.Pointer
}

// getInterfaces extracts all the interfaces from the objects we
// parsed.
func getInterfaces(typs []Type) []Interface {
	var interfaces []Interface

	for _, typ := range typs {
		// Only types, not variables/constants
		// Only interfaces
		if iface, ok := typ.TypeName.Type().Underlying().(*types.Interface); ok {
			interfaces = append(interfaces, Interface{typ.Object.Name(), iface, typ.Object})
		}
	}

	return interfaces
}

func parseFile(fset *token.FileSet, fileName string) (f *ast.File, err error) {
	astFile, err := parser.ParseFile(fset, fileName, nil, 0)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	return astFile, nil
}

type Context struct {
	allImports map[string]*types.Package
	context    types.Context
}

func NewContext() *Context {
	ctx := &Context{
		allImports: make(map[string]*types.Package),
	}

	ctx.context = types.Context{
		Import: ctx.importer,
	}

	return ctx
}

func (ctx *Context) importer(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
	// types.Importer does not seem to be designed for recursive
	// parsing like we're doing here. Specifically, each nested import
	// will maintain its own imports map. This will lead to duplicate
	// imports and in turn packages, which will lead to funny errors
	// such as "cannot pass argument ip (variable of type net.IP) to
	// variable of type net.IP"
	//
	// To work around this, we keep a global imports map, allImports,
	// to which we add all nested imports, and which we use as the
	// cache, instead of imports.
	//
	// Since all nested imports will also use this importer, there
	// should be no way to end up with duplicate imports.

	// We first try to use GcImport directly. This has the downside of
	// using possibly out-of-date packages, but it has the upside of
	// not having to parse most of the Go standard library.

	buildPkg, buildErr := build.Import(path, ".", 0)
	// If we found no build dir, assume we're dealing with installed
	// but no source. If we found a build dir, only use GcImport if
	// it's in GOROOT. This way we always use up-to-date code for
	// normal packages but avoid parsing the standard library.
	if (buildErr == nil && buildPkg.Goroot) || buildErr != nil {
		pkg, err = types.GcImport(ctx.allImports, path)
		if err == nil {
			// We don't use imports, but per API we have to add the package.
			imports[pkg.Path()] = pkg
			ctx.allImports[pkg.Path()] = pkg
			return pkg, nil
		}
	}

	// See if we already imported this package
	if pkg = ctx.allImports[path]; pkg != nil && pkg.Complete() {
		return pkg, nil
	}

	// allImports failed, try to use go/build
	if buildErr != nil {
		return nil, buildErr
	}

	// TODO check if the .a file is up to date and use it instead
	fmt.Println("we have to build", path, "ourselves")
	fileSet := token.NewFileSet()

	isGoFile := func(d os.FileInfo) bool {
		allFiles := make([]string, 0, len(buildPkg.GoFiles)+len(buildPkg.CgoFiles))
		allFiles = append(allFiles, buildPkg.GoFiles...)
		allFiles = append(allFiles, buildPkg.CgoFiles...)

		for _, file := range allFiles {
			if file == d.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, isGoFile, 0)
	if err != nil {
		return nil, err
	}

	delete(pkgs, "documentation")
	var astPkg *ast.Package
	var name string
	for name, astPkg = range pkgs {
		// Use the first non-main package, or the only package we
		// found.
		//
		// NOTE(dh) I can't think of a reason why there should be
		// multiple packages in a single directory, but ParseDir
		// accommodates for that possibility.
		if len(pkgs) == 1 || name != "main" {
			break
		}
	}

	if astPkg == nil {
		return nil, fmt.Errorf("can't find import: %s", name)
	}

	var ff []*ast.File
	for _, f := range astPkg.Files {
		ff = append(ff, f)
	}

	context := types.Context{
		Import: ctx.importer,
	}

	pkg, err = context.Check(name, fileSet, ff...)
	if err != nil {
		return pkg, err
	}
	if !pkg.Complete() {
		pkg = types.NewPackage(pkg.Pos(), pkg.Path(), pkg.Name(), pkg.Scope(), pkg.Imports(), true)
	}

	imports[path] = pkg
	ctx.allImports[path] = pkg
	return pkg, nil
}

func (ctx *Context) getTypes(paths ...string) []Type {
	var typs []Type

	for _, path := range paths {
		buildPkg, err := build.Import(path, ".", 0)
		if err != nil {
			// FIXME better error handling
			fmt.Printf("Couldn't import %s: %s\n", path, err)
			continue
		}
		fset := token.NewFileSet()
		var astFiles []*ast.File
		var pkg *types.Package
		if buildPkg.Goroot {
			// TODO what if the compiled package in GoRoot is
			// outdated?
			fmt.Println("GcImport", path)
			pkg, err = types.GcImport(ctx.allImports, path)
			if err != nil {
				// TODO better error handling
				fmt.Printf("Couldn't import %s: %s\n", path, err)
				continue
			}
		} else {
			fmt.Println("Manual parsing", path)
			if len(buildPkg.GoFiles) == 0 {
				// TODO proper error handling
				fmt.Printf("Couldn't parse %s: No go files\n", path)
				continue
			}
			for _, file := range buildPkg.GoFiles {
				astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file))
				if err != nil {
					// TODO proper error handling
					fmt.Printf("Couldn't parse %s: %s", err)
					continue
				}
				astFiles = append(astFiles, astFile)
			}

			pkg, err = check(ctx, astFiles[0].Name.Name, fset, astFiles)
			if err != nil {
				// FIXME better error handling
				fmt.Printf("Couldn't parse %s: %s\n", path, err)
				continue
			}
			fmt.Println(pkg.Name(), pkg.Complete())
		}

		scope := pkg.Scope()
		for i := 0; i < scope.NumEntries(); i++ {
			obj := scope.At(i)

			// Only types, not variables/constants
			if typ, ok := obj.(*types.TypeName); ok {
				typs = append(typs, Type{
					Object:   obj,
					TypeName: typ,
					Pointer:  types.NewPointer(typ.Type()),
				})
			}

		}
	}
	return typs
}

func check(ctx *Context, name string, fset *token.FileSet, astFiles []*ast.File) (pkg *types.Package, err error) {
	return ctx.context.Check(name, fset, astFiles...)
}

func main() {
	if own == "" {
		flag.Usage()
		os.Exit(1)
	}

	ctx := NewContext()
	stdlib := ctx.getTypes(matchPackages(universe)...)
	toCheck := ctx.getTypes(matchPackages(own)...)

	interfaces := getInterfaces(stdlib)

	for _, typ := range toCheck {
		var implements []string
		var implementsPointer []string
		for _, iface := range interfaces {
			if iface.Underlying.NumMethods() == 0 {
				// Everything implements empty interfaces, skip those
				continue
			}

			if typ.Object.Pkg() == iface.Obj.Pkg() && typ.Object.Name() == iface.Name {
				// An interface will always implement itself, so skip those
				continue
			}

			if fnc, _ := types.MissingMethod(typ.Object.Type(), iface.Underlying); fnc == nil {
				s := fmt.Sprintf("%s.%s",
					iface.Obj.Pkg().Name(), iface.Name)
				implements = append(implements, s)
			}

			// TODO DRY
			if fnc, _ := types.MissingMethod(typ.Pointer.Underlying(), iface.Underlying); fnc == nil {
				s := fmt.Sprintf("%s.%s",
					iface.Obj.Pkg().Name(), iface.Name)
				implementsPointer = append(implementsPointer, s)
			}
		}

		if len(implements) > 0 {
			fmt.Printf("%s.%s implements...\n", typ.TypeName.Pkg().Name(), typ.Object.Name())
			for _, impl := range implements {
				fmt.Printf("\t%s\n", impl)
			}
		}
		// TODO DRY
		if len(implementsPointer) > 0 {
			fmt.Printf("*%s.%s implements...\n", typ.TypeName.Pkg().Name(), typ.Object.Name())
			for _, impl := range implementsPointer {
				fmt.Printf("\t%s\n", impl)
			}
		}
	}
}
<|endoftext|>