<commit_before>// Copyright 2019 Google LLC 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 (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"agones.dev/agones/pkg"
	"agones.dev/agones/pkg/allocation/converters"
	pb "agones.dev/agones/pkg/allocation/go"
	allocationv1 "agones.dev/agones/pkg/apis/allocation/v1"
	"agones.dev/agones/pkg/client/clientset/versioned"
	"agones.dev/agones/pkg/client/informers/externalversions"
	"agones.dev/agones/pkg/gameserverallocations"
	"agones.dev/agones/pkg/gameservers"
	"agones.dev/agones/pkg/util/runtime"
	"agones.dev/agones/pkg/util/signals"
	"github.com/heptiolabs/healthcheck"
	"github.com/pkg/errors"
	"go.opencensus.io/plugin/ocgrpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/grpc/status"
	"gopkg.in/fsnotify.v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8sruntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

var (
	logger = runtime.NewLoggerWithSource("main")
)

const (
	certDir = "/home/allocator/client-ca/"
	tlsDir  = "/home/allocator/tls/"
	sslPort = "8443"
)

func main() {
	conf := parseEnvFlags()

	logger.WithField("version", pkg.Version).WithField("ctlConf", conf).
		WithField("featureGates", runtime.EncodeFeatures()).WithField("sslPort", sslPort).
		Info("Starting agones-allocator")

	health, closer := setupMetricsRecorder(conf)
	defer closer()

	// http.DefaultServerMux is used for http connection, not for https
	http.Handle("/", health)

	kubeClient, agonesClient, err := getClients()
	if err != nil {
		logger.WithError(err).Fatal("could not create clients")
	}

	// This will test the connection to agones on each readiness probe
	// so if one of the allocator pod can't reach Kubernetes it will be removed
	// from the Kubernetes service.
	health.AddReadinessCheck("allocator-agones-client", func() error {
		_, err := agonesClient.ServerVersion()
		return err
	})

	h := newServiceHandler(kubeClient, agonesClient, health, conf.MTLSDisabled, conf.TLSDisabled)

	listener, err := net.Listen("tcp", fmt.Sprintf(":%s", sslPort))
	if err != nil {
		logger.WithError(err).Fatalf("failed to listen on TCP port %s", sslPort)
	}

	if !h.tlsDisabled {
		watcherTLS, err := fsnotify.NewWatcher()
		if err != nil {
			logger.WithError(err).Fatal("could not create watcher for tls certs")
		}
		defer watcherTLS.Close() // nolint: errcheck
		if err := watcherTLS.Add(tlsDir); err != nil {
			logger.WithError(err).Fatalf("cannot watch folder %s for secret changes", tlsDir)
		}

		// Watching for the events in certificate directory for updating certificates, when there is a change
		go func() {
			for {
				select {
				// watch for events
				case event := <-watcherTLS.Events:
					tlsCert, err := readTLSCert()
					if err != nil {
						logger.WithError(err).Error("could not load TLS cert; keeping old one")
					} else {
						h.tlsMutex.Lock()
						h.tlsCert = tlsCert
						h.tlsMutex.Unlock()
					}
					logger.Infof("Tls directory change event %v", event)

				// watch for errors
				case err := <-watcherTLS.Errors:
					logger.WithError(err).Error("error watching for TLS directory")
				}
			}
		}()

		if !h.mTLSDisabled {
			// creates a new file watcher for client certificate folder
			watcher, err := fsnotify.NewWatcher()
			if err != nil {
				logger.WithError(err).Fatal("could not create watcher for client certs")
			}
			defer watcher.Close() // nolint: errcheck
			if err := watcher.Add(certDir); err != nil {
				logger.WithError(err).Fatalf("cannot watch folder %s for secret changes", certDir)
			}

			go func() {
				for {
					select {
					// watch for events
					case event := <-watcher.Events:
						h.certMutex.Lock()
						caCertPool, err := getCACertPool(certDir)
						if err != nil {
							logger.WithError(err).Error("could not load CA certs; keeping old ones")
						} else {
							h.caCertPool = caCertPool
						}
						logger.Infof("Certificate directory change event %v", event)
						h.certMutex.Unlock()

					// watch for errors
					case err := <-watcher.Errors:
						logger.WithError(err).Error("error watching for certificate directory")
					}
				}
			}()
		}
	}

	opts := h.getServerOptions()

	grpcServer := grpc.NewServer(opts...)
	pb.RegisterAllocationServiceServer(grpcServer, h)

	// serve GRPC for allocation
	go func() {
		err := grpcServer.Serve(listener)
		logger.WithError(err).Fatal("allocation service crashed")
		os.Exit(1)
	}()

	// Finally listen on 8080 (http) and block the main goroutine
	// this is used to serve /live and /ready handlers for Kubernetes probes.
	err = http.ListenAndServe(":8080", http.DefaultServeMux)
	logger.WithError(err).Fatal("allocation service crashed")
}

func newServiceHandler(kubeClient kubernetes.Interface, agonesClient versioned.Interface, health healthcheck.Handler, mTLSDisabled bool, tlsDisabled bool) *serviceHandler {
	defaultResync := 30 * time.Second
	agonesInformerFactory := externalversions.NewSharedInformerFactory(agonesClient, defaultResync)
	kubeInformerFactory := informers.NewSharedInformerFactory(kubeClient, defaultResync)
	gsCounter := gameservers.NewPerNodeCounter(kubeInformerFactory, agonesInformerFactory)

	allocator := gameserverallocations.NewAllocator(
		agonesInformerFactory.Multicluster().V1().GameServerAllocationPolicies(),
		kubeInformerFactory.Core().V1().Secrets(),
		kubeClient,
		gameserverallocations.NewReadyGameServerCache(agonesInformerFactory.Agones().V1().GameServers(), agonesClient.AgonesV1(), gsCounter, health))

	stop := signals.NewStopChannel()
	h := serviceHandler{
		allocationCallback: func(gsa *allocationv1.GameServerAllocation) (k8sruntime.Object, error) {
			return allocator.Allocate(gsa, stop)
		},
		mTLSDisabled: mTLSDisabled,
		tlsDisabled:  tlsDisabled,
	}

	kubeInformerFactory.Start(stop)
	agonesInformerFactory.Start(stop)
	if err := allocator.Start(stop); err != nil {
		logger.WithError(err).Fatal("starting allocator failed.")
	}

	if !h.tlsDisabled {
		tlsCert, err := readTLSCert()
		if err != nil {
			logger.WithError(err).Fatal("could not load TLS certs.")
		}
		h.tlsMutex.Lock()
		h.tlsCert = tlsCert
		h.tlsMutex.Unlock()

		if !h.mTLSDisabled {
			caCertPool, err := getCACertPool(certDir)
			if err != nil {
				logger.WithError(err).Fatal("could not load CA certs.")
			}
			h.certMutex.Lock()
			h.caCertPool = caCertPool
			h.certMutex.Unlock()
		}
	}

	return &h
}

func readTLSCert() (*tls.Certificate, error) {
	tlsCert, err := tls.LoadX509KeyPair(tlsDir+"tls.crt", tlsDir+"tls.key")
	if err != nil {
		return nil, err
	}
	return &tlsCert, nil
}

// getServerOptions returns a list of GRPC server options.
// Current options are TLS certs and opencensus stats handler.
func (h *serviceHandler) getServerOptions() []grpc.ServerOption {
	if h.tlsDisabled {
		return []grpc.ServerOption{grpc.StatsHandler(&ocgrpc.ServerHandler{})}
	}

	cfg := &tls.Config{
		GetCertificate: h.getTLSCert,
	}

	if !h.mTLSDisabled {
		cfg.ClientAuth = tls.RequireAnyClientCert
		cfg.VerifyPeerCertificate = h.verifyClientCertificate
	}

	// Add options for creds and  OpenCensus stats handler to enable stats and tracing.
	// The keepalive options are useful for efficiency purposes (keeping a single connection alive
	// instead of constantly recreating connections), when placing the Agones allocator behind load balancers.
	return []grpc.ServerOption{
		grpc.Creds(credentials.NewTLS(cfg)),
		grpc.StatsHandler(&ocgrpc.ServerHandler{}),
		grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
			MinTime:             1 * time.Minute,
			PermitWithoutStream: true,
		}),
		grpc.KeepaliveParams(keepalive.ServerParameters{
			MaxConnectionIdle: 5 * time.Minute,
			Timeout:           10 * time.Minute,
		}),
	}
}

func (h *serviceHandler) getTLSCert(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
	h.tlsMutex.RLock()
	defer h.tlsMutex.RUnlock()
	return h.tlsCert, nil
}

// verifyClientCertificate verifies that the client certificate is accepted
// This method is used as GetConfigForClient is cross lang incompatible.
func (h *serviceHandler) verifyClientCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
	opts := x509.VerifyOptions{
		Roots:         h.caCertPool,
		CurrentTime:   time.Now(),
		Intermediates: x509.NewCertPool(),
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}

	for _, cert := range rawCerts[1:] {
		opts.Intermediates.AppendCertsFromPEM(cert)
	}

	c, err := x509.ParseCertificate(rawCerts[0])
	if err != nil {
		return errors.New("bad client certificate: " + err.Error())
	}

	h.certMutex.RLock()
	defer h.certMutex.RUnlock()
	_, err = c.Verify(opts)
	if err != nil {
		return errors.New("failed to verify client certificate: " + err.Error())
	}
	return nil
}

// Set up our client which we will use to call the API
func getClients() (*kubernetes.Clientset, *versioned.Clientset, error) {
	// Create the in-cluster config
	config, err := rest.InClusterConfig()
	if err != nil {
		return nil, nil, errors.New("Could not create in cluster config")
	}

	// Access to the Agones resources through the Agones Clientset
	kubeClient, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, nil, errors.New("Could not create the kubernetes api clientset")
	}

	// Access to the Agones resources through the Agones Clientset
	agonesClient, err := versioned.NewForConfig(config)
	if err != nil {
		return nil, nil, errors.New("Could not create the agones api clientset")
	}
	return kubeClient, agonesClient, nil
}

func getCACertPool(path string) (*x509.CertPool, error) {
	// Add all certificates under client-certs path because there could be multiple clusters
	// and all client certs should be added.
	caCertPool := x509.NewCertPool()
	filesInfo, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, fmt.Errorf("error reading certs from dir %s: %s", path, err.Error())
	}

	for _, file := range filesInfo {
		if !strings.HasSuffix(file.Name(), ".crt") && !strings.HasSuffix(file.Name(), ".pem") {
			continue
		}
		certFile := filepath.Join(path, file.Name())
		caCert, err := ioutil.ReadFile(certFile)
		if err != nil {
			logger.Errorf("CA cert is not readable or missing: %s", err.Error())
			continue
		}
		if !caCertPool.AppendCertsFromPEM(caCert) {
			logger.Errorf("client cert %s cannot be installed", certFile)
			continue
		}
		logger.Infof("client cert %s is installed", certFile)
	}

	return caCertPool, nil
}

type serviceHandler struct {
	allocationCallback func(*allocationv1.GameServerAllocation) (k8sruntime.Object, error)

	certMutex  sync.RWMutex
	caCertPool *x509.CertPool

	tlsMutex sync.RWMutex
	tlsCert  *tls.Certificate

	mTLSDisabled bool
	tlsDisabled  bool
}

// Allocate implements the Allocate gRPC method definition
func (h *serviceHandler) Allocate(ctx context.Context, in *pb.AllocationRequest) (*pb.AllocationResponse, error) {
	logger.WithField("request", in).Infof("allocation request received.")
	gsa := converters.ConvertAllocationRequestToGSA(in)
	resultObj, err := h.allocationCallback(gsa)
	if err != nil {
		logger.WithField("gsa", gsa).WithError(err).Info("allocation failed")
		return nil, err
	}

	if s, ok := resultObj.(*metav1.Status); ok {
		return nil, status.Errorf(codes.Code(s.Code), s.Message, resultObj)
	}

	allocatedGsa, ok := resultObj.(*allocationv1.GameServerAllocation)
	if !ok {
		logger.Errorf("internal server error - Bad GSA format %v", resultObj)
		return nil, status.Errorf(codes.Internal, "internal server error- Bad GSA format %v", resultObj)
	}
	response, err := converters.ConvertGSAToAllocationResponse(allocatedGsa)
	logger.WithField("response", response).WithError(err).Infof("allocation response is being sent")

	return response, err
}
<commit_msg>Update main.go (#1812)<commit_after>// Copyright 2019 Google LLC 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 (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"agones.dev/agones/pkg"
	"agones.dev/agones/pkg/allocation/converters"
	pb "agones.dev/agones/pkg/allocation/go"
	allocationv1 "agones.dev/agones/pkg/apis/allocation/v1"
	"agones.dev/agones/pkg/client/clientset/versioned"
	"agones.dev/agones/pkg/client/informers/externalversions"
	"agones.dev/agones/pkg/gameserverallocations"
	"agones.dev/agones/pkg/gameservers"
	"agones.dev/agones/pkg/util/runtime"
	"agones.dev/agones/pkg/util/signals"
	"github.com/heptiolabs/healthcheck"
	"github.com/pkg/errors"
	"go.opencensus.io/plugin/ocgrpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/grpc/status"
	"gopkg.in/fsnotify.v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8sruntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

var (
	logger = runtime.NewLoggerWithSource("main")
)

const (
	certDir = "/home/allocator/client-ca/"
	tlsDir  = "/home/allocator/tls/"
	sslPort = "8443"
)

func main() {
	conf := parseEnvFlags()

	logger.WithField("version", pkg.Version).WithField("ctlConf", conf).
		WithField("featureGates", runtime.EncodeFeatures()).WithField("sslPort", sslPort).
		Info("Starting agones-allocator")

	health, closer := setupMetricsRecorder(conf)
	defer closer()

	// http.DefaultServerMux is used for http connection, not for https
	http.Handle("/", health)

	kubeClient, agonesClient, err := getClients()
	if err != nil {
		logger.WithError(err).Fatal("could not create clients")
	}

	// This will test the connection to agones on each readiness probe
	// so if one of the allocator pod can't reach Kubernetes it will be removed
	// from the Kubernetes service.
	health.AddReadinessCheck("allocator-agones-client", func() error {
		_, err := agonesClient.ServerVersion()
		return err
	})

	h := newServiceHandler(kubeClient, agonesClient, health, conf.MTLSDisabled, conf.TLSDisabled)

	listener, err := net.Listen("tcp", fmt.Sprintf(":%s", sslPort))
	if err != nil {
		logger.WithError(err).Fatalf("failed to listen on TCP port %s", sslPort)
	}

	if !h.tlsDisabled {
		watcherTLS, err := fsnotify.NewWatcher()
		if err != nil {
			logger.WithError(err).Fatal("could not create watcher for tls certs")
		}
		defer watcherTLS.Close() // nolint: errcheck
		if err := watcherTLS.Add(tlsDir); err != nil {
			logger.WithError(err).Fatalf("cannot watch folder %s for secret changes", tlsDir)
		}

		// Watching for the events in certificate directory for updating certificates, when there is a change
		go func() {
			for {
				select {
				// watch for events
				case event := <-watcherTLS.Events:
					tlsCert, err := readTLSCert()
					if err != nil {
						logger.WithError(err).Error("could not load TLS cert; keeping old one")
					} else {
						h.tlsMutex.Lock()
						h.tlsCert = tlsCert
						h.tlsMutex.Unlock()
					}
					logger.Infof("Tls directory change event %v", event)

				// watch for errors
				case err := <-watcherTLS.Errors:
					logger.WithError(err).Error("error watching for TLS directory")
				}
			}
		}()

		if !h.mTLSDisabled {
			// creates a new file watcher for client certificate folder
			watcher, err := fsnotify.NewWatcher()
			if err != nil {
				logger.WithError(err).Fatal("could not create watcher for client certs")
			}
			defer watcher.Close() // nolint: errcheck
			if err := watcher.Add(certDir); err != nil {
				logger.WithError(err).Fatalf("cannot watch folder %s for secret changes", certDir)
			}

			go func() {
				for {
					select {
					// watch for events
					case event := <-watcher.Events:
						h.certMutex.Lock()
						caCertPool, err := getCACertPool(certDir)
						if err != nil {
							logger.WithError(err).Error("could not load CA certs; keeping old ones")
						} else {
							h.caCertPool = caCertPool
						}
						logger.Infof("Certificate directory change event %v", event)
						h.certMutex.Unlock()

					// watch for errors
					case err := <-watcher.Errors:
						logger.WithError(err).Error("error watching for certificate directory")
					}
				}
			}()
		}
	}

	opts := h.getServerOptions()

	grpcServer := grpc.NewServer(opts...)
	pb.RegisterAllocationServiceServer(grpcServer, h)

	// serve GRPC for allocation
	go func() {
		err := grpcServer.Serve(listener)
		logger.WithError(err).Fatal("allocation service crashed")
		os.Exit(1)
	}()

	// Finally listen on 8080 (http) and block the main goroutine
	// this is used to serve /live and /ready handlers for Kubernetes probes.
	err = http.ListenAndServe(":8080", http.DefaultServeMux)
	logger.WithError(err).Fatal("allocation service crashed")
}

func newServiceHandler(kubeClient kubernetes.Interface, agonesClient versioned.Interface, health healthcheck.Handler, mTLSDisabled bool, tlsDisabled bool) *serviceHandler {
	defaultResync := 30 * time.Second
	agonesInformerFactory := externalversions.NewSharedInformerFactory(agonesClient, defaultResync)
	kubeInformerFactory := informers.NewSharedInformerFactory(kubeClient, defaultResync)
	gsCounter := gameservers.NewPerNodeCounter(kubeInformerFactory, agonesInformerFactory)

	allocator := gameserverallocations.NewAllocator(
		agonesInformerFactory.Multicluster().V1().GameServerAllocationPolicies(),
		kubeInformerFactory.Core().V1().Secrets(),
		kubeClient,
		gameserverallocations.NewReadyGameServerCache(agonesInformerFactory.Agones().V1().GameServers(), agonesClient.AgonesV1(), gsCounter, health))

	stop := signals.NewStopChannel()
	h := serviceHandler{
		allocationCallback: func(gsa *allocationv1.GameServerAllocation) (k8sruntime.Object, error) {
			return allocator.Allocate(gsa, stop)
		},
		mTLSDisabled: mTLSDisabled,
		tlsDisabled:  tlsDisabled,
	}

	kubeInformerFactory.Start(stop)
	agonesInformerFactory.Start(stop)
	if err := allocator.Start(stop); err != nil {
		logger.WithError(err).Fatal("starting allocator failed.")
	}

	if !h.tlsDisabled {
		tlsCert, err := readTLSCert()
		if err != nil {
			logger.WithError(err).Fatal("could not load TLS certs.")
		}
		h.tlsMutex.Lock()
		h.tlsCert = tlsCert
		h.tlsMutex.Unlock()

		if !h.mTLSDisabled {
			caCertPool, err := getCACertPool(certDir)
			if err != nil {
				logger.WithError(err).Fatal("could not load CA certs.")
			}
			h.certMutex.Lock()
			h.caCertPool = caCertPool
			h.certMutex.Unlock()
		}
	}

	return &h
}

func readTLSCert() (*tls.Certificate, error) {
	tlsCert, err := tls.LoadX509KeyPair(tlsDir+"tls.crt", tlsDir+"tls.key")
	if err != nil {
		return nil, err
	}
	return &tlsCert, nil
}

// getServerOptions returns a list of GRPC server options.
// Current options are TLS certs and opencensus stats handler.
func (h *serviceHandler) getServerOptions() []grpc.ServerOption {
	if h.tlsDisabled {
		return []grpc.ServerOption{grpc.StatsHandler(&ocgrpc.ServerHandler{})}
	}

	cfg := &tls.Config{
		GetCertificate: h.getTLSCert,
	}

	if !h.mTLSDisabled {
		cfg.ClientAuth = tls.RequireAnyClientCert
		cfg.VerifyPeerCertificate = h.verifyClientCertificate
	}

	// Add options for creds and  OpenCensus stats handler to enable stats and tracing.
	// The keepalive options are useful for efficiency purposes (keeping a single connection alive
	// instead of constantly recreating connections), when placing the Agones allocator behind load balancers.
	return []grpc.ServerOption{
		grpc.Creds(credentials.NewTLS(cfg)),
		grpc.StatsHandler(&ocgrpc.ServerHandler{}),
		grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
			MinTime:             1 * time.Minute,
			PermitWithoutStream: true,
		}),
		grpc.KeepaliveParams(keepalive.ServerParameters{
			MaxConnectionIdle: 5 * time.Minute,
			Timeout:           10 * time.Minute,
		}),
	}
}

func (h *serviceHandler) getTLSCert(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
	h.tlsMutex.RLock()
	defer h.tlsMutex.RUnlock()
	return h.tlsCert, nil
}

// verifyClientCertificate verifies that the client certificate is accepted
// This method is used as GetConfigForClient is cross lang incompatible.
func (h *serviceHandler) verifyClientCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
	opts := x509.VerifyOptions{
		Roots:         h.caCertPool,
		CurrentTime:   time.Now(),
		Intermediates: x509.NewCertPool(),
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}

	for _, cert := range rawCerts[1:] {
		opts.Intermediates.AppendCertsFromPEM(cert)
	}

	c, err := x509.ParseCertificate(rawCerts[0])
	if err != nil {
		logger.WithError(err).Warning("cannot parse client certificate")
		return errors.New("bad client certificate: " + err.Error())
	}

	h.certMutex.RLock()
	defer h.certMutex.RUnlock()
	_, err = c.Verify(opts)
	if err != nil {
		logger.WithError(err).Warning("failed to verify client certificate")
		return errors.New("failed to verify client certificate: " + err.Error())
	}
	return nil
}

// Set up our client which we will use to call the API
func getClients() (*kubernetes.Clientset, *versioned.Clientset, error) {
	// Create the in-cluster config
	config, err := rest.InClusterConfig()
	if err != nil {
		return nil, nil, errors.New("Could not create in cluster config")
	}

	// Access to the Agones resources through the Agones Clientset
	kubeClient, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, nil, errors.New("Could not create the kubernetes api clientset")
	}

	// Access to the Agones resources through the Agones Clientset
	agonesClient, err := versioned.NewForConfig(config)
	if err != nil {
		return nil, nil, errors.New("Could not create the agones api clientset")
	}
	return kubeClient, agonesClient, nil
}

func getCACertPool(path string) (*x509.CertPool, error) {
	// Add all certificates under client-certs path because there could be multiple clusters
	// and all client certs should be added.
	caCertPool := x509.NewCertPool()
	filesInfo, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, fmt.Errorf("error reading certs from dir %s: %s", path, err.Error())
	}

	for _, file := range filesInfo {
		if !strings.HasSuffix(file.Name(), ".crt") && !strings.HasSuffix(file.Name(), ".pem") {
			continue
		}
		certFile := filepath.Join(path, file.Name())
		caCert, err := ioutil.ReadFile(certFile)
		if err != nil {
			logger.Errorf("CA cert is not readable or missing: %s", err.Error())
			continue
		}
		if !caCertPool.AppendCertsFromPEM(caCert) {
			logger.Errorf("client cert %s cannot be installed", certFile)
			continue
		}
		logger.Infof("client cert %s is installed", certFile)
	}

	return caCertPool, nil
}

type serviceHandler struct {
	allocationCallback func(*allocationv1.GameServerAllocation) (k8sruntime.Object, error)

	certMutex  sync.RWMutex
	caCertPool *x509.CertPool

	tlsMutex sync.RWMutex
	tlsCert  *tls.Certificate

	mTLSDisabled bool
	tlsDisabled  bool
}

// Allocate implements the Allocate gRPC method definition
func (h *serviceHandler) Allocate(ctx context.Context, in *pb.AllocationRequest) (*pb.AllocationResponse, error) {
	logger.WithField("request", in).Infof("allocation request received.")
	gsa := converters.ConvertAllocationRequestToGSA(in)
	resultObj, err := h.allocationCallback(gsa)
	if err != nil {
		logger.WithField("gsa", gsa).WithError(err).Info("allocation failed")
		return nil, err
	}

	if s, ok := resultObj.(*metav1.Status); ok {
		return nil, status.Errorf(codes.Code(s.Code), s.Message, resultObj)
	}

	allocatedGsa, ok := resultObj.(*allocationv1.GameServerAllocation)
	if !ok {
		logger.Errorf("internal server error - Bad GSA format %v", resultObj)
		return nil, status.Errorf(codes.Internal, "internal server error- Bad GSA format %v", resultObj)
	}
	response, err := converters.ConvertGSAToAllocationResponse(allocatedGsa)
	logger.WithField("response", response).WithError(err).Infof("allocation response is being sent")

	return response, err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/bradleyfalzon/apicompat"
)

func main() {
	// TODO print CLI arguments, note that it does support GOARCH, GOOS, GOPATH etc, ./... works too
	before := flag.String("before", "", "Compare revision before, leave unset for the VCS default or . to bypass VCS and use filesystem version")
	after := flag.String("after", "", "Compare revision after, leave unset for the VCS default or . to bypass VCS and use filesystem version")
	excludeFile := flag.String("exclude-file", "", "Exclude files based on regexp pattern")
	excludeDir := flag.String("exclude-dir", "", "Exclude directory based on regexp pattern")
	allChanges := flag.Bool("all", false, "Show all changes, not just breaking")
	verbose := flag.Bool("v", false, "Enable verbose logging")
	flag.Parse()
	path := flag.Arg(0)
	rel, rec, err := apicompat.RelativePathToTarget(path)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// TODO make it auto discover
	git, err := apicompat.NewGit(rel)
	if err != nil {
		fmt.Fprintf(os.Stderr, "apicompat: %s\n", err)
		os.Exit(2)
	}

	args := []func(*apicompat.Checker){apicompat.SetVCS(git)}
	if *verbose {
		args = append(args, apicompat.SetVLog(os.Stdout))
	}
	if *excludeFile != "" {
		args = append(args, apicompat.SetExcludeFile(*excludeFile))
	}
	if *excludeDir != "" {
		args = append(args, apicompat.SetExcludeDir(*excludeDir))
	}

	checker := apicompat.New(args...)
	changes, err := checker.Check(rel, rec, *before, *after)
	if err != nil {
		fmt.Fprintf(os.Stderr, "apicompat: %s\n", err)
		os.Exit(1)
	}

	for _, change := range changes {
		if *allChanges || change.Change == apicompat.Breaking {
			fmt.Println(change)
		}
	}
}
<commit_msg>Revise cmd/apicompat output format and exit codes.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/bradleyfalzon/apicompat"
)

const (
	exitCodeNoError       = 0
	exitCodeInternalError = 1
	exitCodeBreaking      = 2
)

func main() {
	// TODO print CLI arguments, note that it does support GOARCH, GOOS, GOPATH etc, ./... works too
	before := flag.String("before", "", "Compare revision before, leave unset for the VCS default or . to bypass VCS and use filesystem version")
	after := flag.String("after", "", "Compare revision after, leave unset for the VCS default or . to bypass VCS and use filesystem version")
	excludeFile := flag.String("exclude-file", "", "Exclude files based on regexp pattern")
	excludeDir := flag.String("exclude-dir", "", "Exclude directory based on regexp pattern")
	allChanges := flag.Bool("all", false, "Show all changes, not just breaking")
	verbose := flag.Bool("v", false, "Enable verbose logging")
	flag.Parse()
	path := flag.Arg(0)
	rel, rec, err := apicompat.RelativePathToTarget(path)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(exitCodeInternalError)
	}

	// TODO make it auto discover
	git, err := apicompat.NewGit(rel)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(exitCodeInternalError)
	}

	args := []func(*apicompat.Checker){apicompat.SetVCS(git)}
	if *verbose {
		args = append(args, apicompat.SetVLog(os.Stdout))
	}
	if *excludeFile != "" {
		args = append(args, apicompat.SetExcludeFile(*excludeFile))
	}
	if *excludeDir != "" {
		args = append(args, apicompat.SetExcludeDir(*excludeDir))
	}

	checker := apicompat.New(args...)
	changes, err := checker.Check(rel, rec, *before, *after)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(exitCodeInternalError)
	}

	exitCode := exitCodeNoError
	for _, change := range changes {
		switch {
		case change.Change == apicompat.Breaking:
			exitCode = exitCodeBreaking
			fmt.Print(change)
		case *allChanges:
			fmt.Print(change)
		}
	}
	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "github.com/yukkeorg/go-usbio2"
)

func main() {
    usbio, err := usbio2.NewUsbIO2()
    if err != nil {
		log.Printf("USB-IO2.0 not detected.")
        return
    }

    defer usbio.Cleanup()

    config, err := usbio.GetConfig()
    if err != nil {
		log.Printf("Can't read device config.")
        return
    }

    log.Printf("Detected device: %s", usbio.GetDeviceName())
    log.Printf("Pullup Enabled: %v", config.EnablePullUp)
    log.Printf("Port1 Pin Setup (value in 'ture' is a INPUT)")
    for i, b := range config.Port1 {
        log.Printf("  Pin%d: %v", i, b)
    }
    log.Printf("Port2 Pin Setup (value in 'ture' is a INPUT)")
    for i, b := range config.Port2 {
        log.Printf("  Pin%d: %v", i, b)
    }
}
<commit_msg>cmd/getconfig: Tabbed<commit_after>package main

import (
	"log"
	"github.com/yukkeorg/go-usbio2"
)

func main() {
	usbio, err := usbio2.NewUsbIO2()
	if err != nil {
		log.Printf("USB-IO2.0 not detected.")
		return
	}
	defer usbio.Cleanup()

	config, err := usbio.GetConfig()
	if err != nil {
		log.Printf("Can't read device config.")
		return
	}

	log.Printf("Detected device: %s", usbio.GetDeviceName())
	log.Printf("Pullup Enabled: %s", bool2str(config.EnablePullUp, "ENABLE", "DISABLE"))
	log.Printf("Port1 Pin Setup")
	for i, b := range config.Port1 {
		log.Printf("  Pin%d: %s", i, bool2str(b, "INPUT", "OUTPUT"))
	}
	log.Printf("Port2 Pin Setup")
	for i, b := range config.Port2 {
		log.Printf("  Pin%d: %s", i, bool2str(b, "INPUT", "OUTPUT"))
	}
}

func bool2str(b bool, true_str string, false_str string) string {
	if(b) {
		return true_str
	} else {
		return false_str
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// A binary that can morph into all of the other kubernetes binaries. You can
// also soft-link to it busybox style.
//
package main

import (
	"errors"
	goflag "flag"
	"fmt"
	"math/rand"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	cliflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	cloudcontrollermanager "k8s.io/kubernetes/cmd/cloud-controller-manager/app"
	kubeapiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
	kubecontrollermanager "k8s.io/kubernetes/cmd/kube-controller-manager/app"
	kubeproxy "k8s.io/kubernetes/cmd/kube-proxy/app"
	kubescheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
	_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
	kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
	_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
)

func main() {
	rand.Seed(time.Now().UnixNano())

	hyperkubeCommand, allCommandFns := NewHyperKubeCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// cliflag.InitFlags()
	logs.InitLogs()
	defer logs.FlushLogs()

	basename := filepath.Base(os.Args[0])
	if err := commandFor(basename, hyperkubeCommand, allCommandFns).Execute(); err != nil {
		os.Exit(1)
	}
}

func commandFor(basename string, defaultCommand *cobra.Command, commands []func() *cobra.Command) *cobra.Command {
	for _, commandFn := range commands {
		command := commandFn()
		if command.Name() == basename {
			return command
		}
		for _, alias := range command.Aliases {
			if alias == basename {
				return command
			}
		}
	}

	return defaultCommand
}

// NewHyperKubeCommand is the entry point for hyperkube
func NewHyperKubeCommand() (*cobra.Command, []func() *cobra.Command) {
	// these have to be functions since the command is polymorphic. Cobra wants you to be top level
	// command to get executed
	apiserver := func() *cobra.Command { return kubeapiserver.NewAPIServerCommand() }
	controller := func() *cobra.Command { return kubecontrollermanager.NewControllerManagerCommand() }
	proxy := func() *cobra.Command { return kubeproxy.NewProxyCommand() }
	scheduler := func() *cobra.Command { return kubescheduler.NewSchedulerCommand() }
	kubectlCmd := func() *cobra.Command { return kubectl.NewDefaultKubectlCommand() }
	kubelet := func() *cobra.Command { return kubelet.NewKubeletCommand() }
	cloudController := func() *cobra.Command { return cloudcontrollermanager.NewCloudControllerManagerCommand() }

	commandFns := []func() *cobra.Command{
		apiserver,
		controller,
		proxy,
		scheduler,
		kubectlCmd,
		kubelet,
		cloudController,
	}

	makeSymlinksFlag := false
	cmd := &cobra.Command{
		Use:   "hyperkube",
		Short: "Request a new project",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) != 0 || !makeSymlinksFlag {
				cmd.Help()
				os.Exit(1)
			}

			if err := makeSymlinks(os.Args[0], commandFns); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err.Error())
			}
		},
	}
	cmd.Flags().BoolVar(&makeSymlinksFlag, "make-symlinks", makeSymlinksFlag, "create a symlink for each server in current directory")
	cmd.Flags().MarkHidden("make-symlinks") // hide this flag from appearing in servers' usage output
	cmd.Flags().MarkDeprecated("make-symlinks", "This feature will be removed in a later release.")

	for i := range commandFns {
		cmd.AddCommand(commandFns[i]())
	}

	return cmd, commandFns
}

// makeSymlinks will create a symlink for each command in the local directory.
func makeSymlinks(targetName string, commandFns []func() *cobra.Command) error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	var errs bool
	for _, commandFn := range commandFns {
		command := commandFn()
		link := path.Join(wd, command.Name())

		err := os.Symlink(targetName, link)
		if err != nil {
			errs = true
			fmt.Println(err)
		}
	}

	if errs {
		return errors.New("Error creating one or more symlinks")
	}
	return nil
}
<commit_msg>removed make-symlink flag and corresponding code in hyperkube<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// A binary that can morph into all of the other kubernetes binaries. You can
// also soft-link to it busybox style.
//
package main

import (
	goflag "flag"
	"math/rand"
	"os"
	"path/filepath"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	cliflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	cloudcontrollermanager "k8s.io/kubernetes/cmd/cloud-controller-manager/app"
	kubeapiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
	kubecontrollermanager "k8s.io/kubernetes/cmd/kube-controller-manager/app"
	kubeproxy "k8s.io/kubernetes/cmd/kube-proxy/app"
	kubescheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
	kubelet "k8s.io/kubernetes/cmd/kubelet/app"
	_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
	kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
	_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
)

func main() {
	rand.Seed(time.Now().UnixNano())

	hyperkubeCommand, allCommandFns := NewHyperKubeCommand()

	// TODO: once we switch everything over to Cobra commands, we can go back to calling
	// cliflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
	// normalize func and add the go flag set by hand.
	pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	// cliflag.InitFlags()
	logs.InitLogs()
	defer logs.FlushLogs()

	basename := filepath.Base(os.Args[0])
	if err := commandFor(basename, hyperkubeCommand, allCommandFns).Execute(); err != nil {
		os.Exit(1)
	}
}

func commandFor(basename string, defaultCommand *cobra.Command, commands []func() *cobra.Command) *cobra.Command {
	for _, commandFn := range commands {
		command := commandFn()
		if command.Name() == basename {
			return command
		}
		for _, alias := range command.Aliases {
			if alias == basename {
				return command
			}
		}
	}

	return defaultCommand
}

// NewHyperKubeCommand is the entry point for hyperkube
func NewHyperKubeCommand() (*cobra.Command, []func() *cobra.Command) {
	// these have to be functions since the command is polymorphic. Cobra wants you to be top level
	// command to get executed
	apiserver := func() *cobra.Command { return kubeapiserver.NewAPIServerCommand() }
	controller := func() *cobra.Command { return kubecontrollermanager.NewControllerManagerCommand() }
	proxy := func() *cobra.Command { return kubeproxy.NewProxyCommand() }
	scheduler := func() *cobra.Command { return kubescheduler.NewSchedulerCommand() }
	kubectlCmd := func() *cobra.Command { return kubectl.NewDefaultKubectlCommand() }
	kubelet := func() *cobra.Command { return kubelet.NewKubeletCommand() }
	cloudController := func() *cobra.Command { return cloudcontrollermanager.NewCloudControllerManagerCommand() }

	commandFns := []func() *cobra.Command{
		apiserver,
		controller,
		proxy,
		scheduler,
		kubectlCmd,
		kubelet,
		cloudController,
	}

	cmd := &cobra.Command{
		Use:   "hyperkube",
		Short: "Request a new project",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) != 0 {
				cmd.Help()
				os.Exit(1)
			}

		},
	}

	for i := range commandFns {
		cmd.AddCommand(commandFns[i]())
	}

	return cmd, commandFns
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/filter"
	"github.com/Symantec/Dominator/lib/flagutil"
	objectclient "github.com/Symantec/Dominator/lib/objectserver/client"
	"github.com/Symantec/Dominator/lib/srpc"
	"net/rpc"
	"os"
	"path"
)

var (
	buildLog = flag.String("buildLog", "",
		"Filename or URL containing build log")
	certFile = flag.String("certFile",
		path.Join(os.Getenv("HOME"), ".ssl/cert.pem"),
		"Name of file containing the user SSL certificate")
	computedFiles = flag.String("computedFiles", "",
		"Name of file containing computed files list")
	debug = flag.Bool("debug", false,
		"If true, show debugging output")
	deleteFilter = flag.String("deleteFilter", "",
		"Name of delete filter file for addi, adds subcommand and right image")
	filterFile = flag.String("filterFile", "",
		"Filter file to apply when diffing images")
	imageServerHostname = flag.String("imageServerHostname", "localhost",
		"Hostname of image server")
	imageServerPortNum = flag.Uint("imageServerPortNum",
		constants.ImageServerPortNumber,
		"Port number of image server")
	keyFile = flag.String("keyFile",
		path.Join(os.Getenv("HOME"), ".ssl/key.pem"),
		"Name of file containing the user SSL key")
	releaseNotes = flag.String("releaseNotes", "",
		"Filename or URL containing release notes")
	requiredPaths = flagutil.StringToRuneMap(constants.RequiredPaths)
	skipFields    = flag.String("skipFields", "",
		"Fields to skip when showing or diffing images")
)

func init() {
	flag.Var(&requiredPaths, "requiredPaths",
		"Comma separated list of required path:type entries")
}

func printUsage() {
	fmt.Fprintln(os.Stderr,
		"Usage: imagetool [flags...] add|check|delete|list [args...]")
	fmt.Fprintln(os.Stderr, "Common flags:")
	flag.PrintDefaults()
	fmt.Fprintln(os.Stderr, "Commands:")
	fmt.Fprintln(os.Stderr, "  add    name imagefile filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  addi   name imagename filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  adds   name subname filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  addrep name baseimage layerimage...")
	fmt.Fprintln(os.Stderr, "  bulk-addrep layerimage...")
	fmt.Fprintln(os.Stderr, "  check  name")
	fmt.Fprintln(os.Stderr, "  delete name")
	fmt.Fprintln(os.Stderr, "  diff   tool left right")
	fmt.Fprintln(os.Stderr, "         left & right are image sources. Format:")
	fmt.Fprintln(os.Stderr, "         type:name where type is one of:")
	fmt.Fprintln(os.Stderr, "           f: name of file containing an image")
	fmt.Fprintln(os.Stderr, "           i: name of an image on the imageserver")
	fmt.Fprintln(os.Stderr, "           s: name of sub to poll")
	fmt.Fprintln(os.Stderr, "  get    name directory")
	fmt.Fprintln(os.Stderr, "  list")
	fmt.Fprintln(os.Stderr, "  show   name")
	fmt.Fprintln(os.Stderr, "Fields:")
	fmt.Fprintln(os.Stderr, "  m: mode")
	fmt.Fprintln(os.Stderr, "  l: number of hardlinks")
	fmt.Fprintln(os.Stderr, "  u: UID")
	fmt.Fprintln(os.Stderr, "  g: GID")
	fmt.Fprintln(os.Stderr, "  s: size/Rdev")
	fmt.Fprintln(os.Stderr, "  t: time of last modification")
	fmt.Fprintln(os.Stderr, "  n: name")
	fmt.Fprintln(os.Stderr, "  d: data (hash or symlink target)")
}

type commandFunc func([]string)

type subcommand struct {
	command string
	minArgs int
	maxArgs int
	cmdFunc commandFunc
}

var subcommands = []subcommand{
	{"add", 4, 4, addImagefileSubcommand},
	{"adds", 4, 4, addImagesubSubcommand},
	{"addi", 4, 4, addImageimageSubcommand},
	{"addrep", 3, -1, addReplaceImageSubcommand},
	{"bulk-addrep", 1, -1, bulkAddReplaceImagesSubcommand},
	{"check", 1, 1, checkImageSubcommand},
	{"delete", 1, 1, deleteImageSubcommand},
	{"diff", 3, 3, diffSubcommand},
	{"get", 2, 2, getImageSubcommand},
	{"list", 0, 0, listImagesSubcommand},
	{"show", 1, 0, showImageSubcommand},
}

var imageRpcClient *rpc.Client
var imageSrpcClient *srpc.Client
var theObjectClient *objectclient.ObjectClient

var listSelector filesystem.ListSelector

func getClients() (*rpc.Client, *srpc.Client, *objectclient.ObjectClient) {
	if imageRpcClient == nil {
		var err error
		clientName := fmt.Sprintf("%s:%d",
			*imageServerHostname, *imageServerPortNum)
		imageRpcClient, err = rpc.DialHTTP("tcp", clientName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error dialing\t%s\n", err)
			os.Exit(1)
		}
		imageSrpcClient, err = srpc.DialHTTP("tcp", clientName, 0)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error dialing\t%s\n", err)
			os.Exit(1)
		}
		theObjectClient = objectclient.NewObjectClient(clientName)
	}
	return imageRpcClient, imageSrpcClient, theObjectClient
}

func makeListSelector(arg string) filesystem.ListSelector {
	var mask filesystem.ListSelector = filesystem.ListSelectAll
	for _, char := range arg {
		switch char {
		case 'm':
			mask |= filesystem.ListSelectSkipMode
		case 'l':
			mask |= filesystem.ListSelectSkipNumLinks
		case 'u':
			mask |= filesystem.ListSelectSkipUid
		case 'g':
			mask |= filesystem.ListSelectSkipGid
		case 's':
			mask |= filesystem.ListSelectSkipSizeDevnum
		case 't':
			mask |= filesystem.ListSelectSkipMtime
		case 'n':
			mask |= filesystem.ListSelectSkipName
		case 'd':
			mask |= filesystem.ListSelectSkipData
		}
	}
	return mask
}

var listFilter *filter.Filter

func main() {
	flag.Usage = printUsage
	flag.Parse()
	if flag.NArg() < 1 {
		printUsage()
		os.Exit(2)
	}
	listSelector = makeListSelector(*skipFields)
	var err error
	if *filterFile != "" {
		listFilter, err = filter.LoadFilter(*filterFile)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}
	}
	setupTls(*certFile, *keyFile)
	numSubcommandArgs := flag.NArg() - 1
	for _, subcommand := range subcommands {
		if flag.Arg(0) == subcommand.command {
			if numSubcommandArgs < subcommand.minArgs ||
				(subcommand.maxArgs >= 0 &&
					numSubcommandArgs > subcommand.maxArgs) {
				printUsage()
				os.Exit(2)
			}
			subcommand.cmdFunc(flag.Args()[1:])
			os.Exit(3)
		}
	}
	printUsage()
	os.Exit(2)
}
<commit_msg>Fix bug in imagetool: show subcommand was disabled.<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/filter"
	"github.com/Symantec/Dominator/lib/flagutil"
	objectclient "github.com/Symantec/Dominator/lib/objectserver/client"
	"github.com/Symantec/Dominator/lib/srpc"
	"net/rpc"
	"os"
	"path"
)

var (
	buildLog = flag.String("buildLog", "",
		"Filename or URL containing build log")
	certFile = flag.String("certFile",
		path.Join(os.Getenv("HOME"), ".ssl/cert.pem"),
		"Name of file containing the user SSL certificate")
	computedFiles = flag.String("computedFiles", "",
		"Name of file containing computed files list")
	debug = flag.Bool("debug", false,
		"If true, show debugging output")
	deleteFilter = flag.String("deleteFilter", "",
		"Name of delete filter file for addi, adds subcommand and right image")
	filterFile = flag.String("filterFile", "",
		"Filter file to apply when diffing images")
	imageServerHostname = flag.String("imageServerHostname", "localhost",
		"Hostname of image server")
	imageServerPortNum = flag.Uint("imageServerPortNum",
		constants.ImageServerPortNumber,
		"Port number of image server")
	keyFile = flag.String("keyFile",
		path.Join(os.Getenv("HOME"), ".ssl/key.pem"),
		"Name of file containing the user SSL key")
	releaseNotes = flag.String("releaseNotes", "",
		"Filename or URL containing release notes")
	requiredPaths = flagutil.StringToRuneMap(constants.RequiredPaths)
	skipFields    = flag.String("skipFields", "",
		"Fields to skip when showing or diffing images")
)

func init() {
	flag.Var(&requiredPaths, "requiredPaths",
		"Comma separated list of required path:type entries")
}

func printUsage() {
	fmt.Fprintln(os.Stderr,
		"Usage: imagetool [flags...] add|check|delete|list [args...]")
	fmt.Fprintln(os.Stderr, "Common flags:")
	flag.PrintDefaults()
	fmt.Fprintln(os.Stderr, "Commands:")
	fmt.Fprintln(os.Stderr, "  add    name imagefile filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  addi   name imagename filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  adds   name subname filterfile triggerfile")
	fmt.Fprintln(os.Stderr, "  addrep name baseimage layerimage...")
	fmt.Fprintln(os.Stderr, "  bulk-addrep layerimage...")
	fmt.Fprintln(os.Stderr, "  check  name")
	fmt.Fprintln(os.Stderr, "  delete name")
	fmt.Fprintln(os.Stderr, "  diff   tool left right")
	fmt.Fprintln(os.Stderr, "         left & right are image sources. Format:")
	fmt.Fprintln(os.Stderr, "         type:name where type is one of:")
	fmt.Fprintln(os.Stderr, "           f: name of file containing an image")
	fmt.Fprintln(os.Stderr, "           i: name of an image on the imageserver")
	fmt.Fprintln(os.Stderr, "           s: name of sub to poll")
	fmt.Fprintln(os.Stderr, "  get    name directory")
	fmt.Fprintln(os.Stderr, "  list")
	fmt.Fprintln(os.Stderr, "  show   name")
	fmt.Fprintln(os.Stderr, "Fields:")
	fmt.Fprintln(os.Stderr, "  m: mode")
	fmt.Fprintln(os.Stderr, "  l: number of hardlinks")
	fmt.Fprintln(os.Stderr, "  u: UID")
	fmt.Fprintln(os.Stderr, "  g: GID")
	fmt.Fprintln(os.Stderr, "  s: size/Rdev")
	fmt.Fprintln(os.Stderr, "  t: time of last modification")
	fmt.Fprintln(os.Stderr, "  n: name")
	fmt.Fprintln(os.Stderr, "  d: data (hash or symlink target)")
}

type commandFunc func([]string)

type subcommand struct {
	command string
	minArgs int
	maxArgs int
	cmdFunc commandFunc
}

var subcommands = []subcommand{
	{"add", 4, 4, addImagefileSubcommand},
	{"adds", 4, 4, addImagesubSubcommand},
	{"addi", 4, 4, addImageimageSubcommand},
	{"addrep", 3, -1, addReplaceImageSubcommand},
	{"bulk-addrep", 1, -1, bulkAddReplaceImagesSubcommand},
	{"check", 1, 1, checkImageSubcommand},
	{"delete", 1, 1, deleteImageSubcommand},
	{"diff", 3, 3, diffSubcommand},
	{"get", 2, 2, getImageSubcommand},
	{"list", 0, 0, listImagesSubcommand},
	{"show", 1, 1, showImageSubcommand},
}

var imageRpcClient *rpc.Client
var imageSrpcClient *srpc.Client
var theObjectClient *objectclient.ObjectClient

var listSelector filesystem.ListSelector

func getClients() (*rpc.Client, *srpc.Client, *objectclient.ObjectClient) {
	if imageRpcClient == nil {
		var err error
		clientName := fmt.Sprintf("%s:%d",
			*imageServerHostname, *imageServerPortNum)
		imageRpcClient, err = rpc.DialHTTP("tcp", clientName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error dialing\t%s\n", err)
			os.Exit(1)
		}
		imageSrpcClient, err = srpc.DialHTTP("tcp", clientName, 0)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error dialing\t%s\n", err)
			os.Exit(1)
		}
		theObjectClient = objectclient.NewObjectClient(clientName)
	}
	return imageRpcClient, imageSrpcClient, theObjectClient
}

func makeListSelector(arg string) filesystem.ListSelector {
	var mask filesystem.ListSelector = filesystem.ListSelectAll
	for _, char := range arg {
		switch char {
		case 'm':
			mask |= filesystem.ListSelectSkipMode
		case 'l':
			mask |= filesystem.ListSelectSkipNumLinks
		case 'u':
			mask |= filesystem.ListSelectSkipUid
		case 'g':
			mask |= filesystem.ListSelectSkipGid
		case 's':
			mask |= filesystem.ListSelectSkipSizeDevnum
		case 't':
			mask |= filesystem.ListSelectSkipMtime
		case 'n':
			mask |= filesystem.ListSelectSkipName
		case 'd':
			mask |= filesystem.ListSelectSkipData
		}
	}
	return mask
}

var listFilter *filter.Filter

func main() {
	flag.Usage = printUsage
	flag.Parse()
	if flag.NArg() < 1 {
		printUsage()
		os.Exit(2)
	}
	listSelector = makeListSelector(*skipFields)
	var err error
	if *filterFile != "" {
		listFilter, err = filter.LoadFilter(*filterFile)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}
	}
	setupTls(*certFile, *keyFile)
	numSubcommandArgs := flag.NArg() - 1
	for _, subcommand := range subcommands {
		if flag.Arg(0) == subcommand.command {
			if numSubcommandArgs < subcommand.minArgs ||
				(subcommand.maxArgs >= 0 &&
					numSubcommandArgs > subcommand.maxArgs) {
				printUsage()
				os.Exit(2)
			}
			subcommand.cmdFunc(flag.Args()[1:])
			os.Exit(3)
		}
	}
	printUsage()
	os.Exit(2)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"path/filepath"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	homedir "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
	fsnotify "github.com/jbenet/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
	commands "github.com/jbenet/go-ipfs/commands"
	core "github.com/jbenet/go-ipfs/core"
	corehttp "github.com/jbenet/go-ipfs/core/corehttp"
	coreunix "github.com/jbenet/go-ipfs/core/coreunix"
	config "github.com/jbenet/go-ipfs/repo/config"
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
)

var http = flag.Bool("http", false, "expose IPFS HTTP API")
var repoPath = flag.String("repo", os.Getenv("IPFS_PATH"), "IPFS_PATH to use")
var watchPath = flag.String("path", ".", "the path to watch")

func main() {
	flag.Parse()

	// precedence
	// 1. --repo flag
	// 2. IPFS_PATH environment variable
	// 3. default repo path
	ipfsPath := config.DefaultPathRoot
	if *repoPath != "" {
		ipfsPath = *repoPath
	}

	if err := run(ipfsPath, *watchPath); err != nil {
		log.Fatal(err)
	}
}

func run(ipfsPath, watchPath string) error {
	log.Printf("running IPFSWatch on %s using repo at %s...", watchPath, ipfsPath)

	ipfsPath, err := homedir.Expand(ipfsPath)
	if err != nil {
		return err
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	defer watcher.Close()

	if err := addTree(watcher, watchPath); err != nil {
		return err
	}

	r := fsrepo.At(ipfsPath)
	if err := r.Open(); err != nil {
		// TODO handle case: daemon running
		// TODO handle case: repo doesn't exist or isn't initialized
		return err
	}
	node, err := core.NewIPFSNode(context.Background(), core.Online(r))
	if err != nil {
		return err
	}
	defer node.Close()

	if *http {
		maddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5001")
		if err != nil {
			return err
		}
		var opts = []corehttp.ServeOption{
			corehttp.GatewayOption,
			corehttp.WebUIOption,
			corehttp.CommandsOption(cmdCtx(node, ipfsPath)),
		}
		if err := corehttp.ListenAndServe(node, maddr, opts...); err != nil {
			return nil
		}
	}

	for {
		select {
		case e := <-watcher.Events:
			log.Printf("received event: %s", e)
			isDir, err := IsDirectory(e.Name)
			if err != nil {
				continue
			}
			switch e.Op {
			case fsnotify.Remove:
				if isDir {
					if err := watcher.Remove(e.Name); err != nil {
						return err
					}
				}
			default:
				// all events except for Remove result in an IPFS.Add, but only
				// directory creation triggers a new watch
				switch e.Op {
				case fsnotify.Create:
					if isDir {
						addTree(watcher, e.Name)
					}
				}
				func() {
					file, err := os.Open(e.Name)
					if err != nil {
						log.Println(err)
					}
					defer file.Close()
					k, err := coreunix.Add(node, file)
					if err != nil {
						log.Println(err)
					}
					log.Printf("added %s... key: %s", e.Name, k)
				}()
			}
		case err := <-watcher.Errors:
			log.Println(err)
		}
	}
	return nil
}

func addTree(w *fsnotify.Watcher, root string) error {
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		isDir, err := IsDirectory(path)
		if err != nil {
			log.Println(err)
			return nil
		}
		switch {
		case isDir && IsHidden(path):
			log.Println(path)
			return filepath.SkipDir
		case isDir:
			log.Println(path)
			if err := w.Add(path); err != nil {
				return err
			}
		default:
			return nil
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}

func IsDirectory(path string) (bool, error) {
	fileInfo, err := os.Stat(path)
	return fileInfo.IsDir(), err
}

func IsHidden(path string) bool {
	path = filepath.Base(path)
	if path == "." || path == "" {
		return false
	}
	if rune(path[0]) == rune('.') {
		return true
	}
	return false
}

func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {
	return commands.Context{
		// TODO deprecate this shit
		Context:    context.Background(),
		Online:     true,
		ConfigRoot: repoPath,
		LoadConfig: func(path string) (*config.Config, error) {
			return node.Repo.Config(), nil
		},
		ConstructNode: func() (*core.IpfsNode, error) {
			return node, nil
		},
	}
}
<commit_msg>shut down cleanly<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"path/filepath"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	process "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
	homedir "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
	fsnotify "github.com/jbenet/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
	commands "github.com/jbenet/go-ipfs/commands"
	core "github.com/jbenet/go-ipfs/core"
	corehttp "github.com/jbenet/go-ipfs/core/corehttp"
	coreunix "github.com/jbenet/go-ipfs/core/coreunix"
	config "github.com/jbenet/go-ipfs/repo/config"
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
)

var http = flag.Bool("http", false, "expose IPFS HTTP API")
var repoPath = flag.String("repo", os.Getenv("IPFS_PATH"), "IPFS_PATH to use")
var watchPath = flag.String("path", ".", "the path to watch")

func main() {
	flag.Parse()

	// precedence
	// 1. --repo flag
	// 2. IPFS_PATH environment variable
	// 3. default repo path
	ipfsPath := config.DefaultPathRoot
	if *repoPath != "" {
		ipfsPath = *repoPath
	}

	if err := run(ipfsPath, *watchPath); err != nil {
		log.Fatal(err)
	}
}

func run(ipfsPath, watchPath string) error {

	proc := process.WithParent(process.Background())
	log.Printf("running IPFSWatch on %s using repo at %s...", watchPath, ipfsPath)

	ipfsPath, err := homedir.Expand(ipfsPath)
	if err != nil {
		return err
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	defer watcher.Close()

	if err := addTree(watcher, watchPath); err != nil {
		return err
	}

	r := fsrepo.At(ipfsPath)
	if err := r.Open(); err != nil {
		// TODO handle case: daemon running
		// TODO handle case: repo doesn't exist or isn't initialized
		return err
	}
	node, err := core.NewIPFSNode(context.Background(), core.Online(r))
	if err != nil {
		return err
	}
	defer node.Close()

	if *http {
		maddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5001")
		if err != nil {
			return err
		}
		var opts = []corehttp.ServeOption{
			corehttp.GatewayOption,
			corehttp.WebUIOption,
			corehttp.CommandsOption(cmdCtx(node, ipfsPath)),
		}
		proc.Go(func(p process.Process) {
			if err := corehttp.ListenAndServe(node, maddr, opts...); err != nil {
				return
			}
		})
	}

	interrupts := make(chan os.Signal)
	signal.Notify(interrupts, os.Interrupt, os.Kill)

	for {
		select {
		case <-interrupts:
			return nil
		case e := <-watcher.Events:
			log.Printf("received event: %s", e)
			isDir, err := IsDirectory(e.Name)
			if err != nil {
				continue
			}
			switch e.Op {
			case fsnotify.Remove:
				if isDir {
					if err := watcher.Remove(e.Name); err != nil {
						return err
					}
				}
			default:
				// all events except for Remove result in an IPFS.Add, but only
				// directory creation triggers a new watch
				switch e.Op {
				case fsnotify.Create:
					if isDir {
						addTree(watcher, e.Name)
					}
				}
				func() {
					file, err := os.Open(e.Name)
					if err != nil {
						log.Println(err)
					}
					defer file.Close()
					k, err := coreunix.Add(node, file)
					if err != nil {
						log.Println(err)
					}
					log.Printf("added %s... key: %s", e.Name, k)
				}()
			}
		case err := <-watcher.Errors:
			log.Println(err)
		}
	}
	return nil
}

func addTree(w *fsnotify.Watcher, root string) error {
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		isDir, err := IsDirectory(path)
		if err != nil {
			log.Println(err)
			return nil
		}
		switch {
		case isDir && IsHidden(path):
			log.Println(path)
			return filepath.SkipDir
		case isDir:
			log.Println(path)
			if err := w.Add(path); err != nil {
				return err
			}
		default:
			return nil
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}

func IsDirectory(path string) (bool, error) {
	fileInfo, err := os.Stat(path)
	return fileInfo.IsDir(), err
}

func IsHidden(path string) bool {
	path = filepath.Base(path)
	if path == "." || path == "" {
		return false
	}
	if rune(path[0]) == rune('.') {
		return true
	}
	return false
}

func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {
	return commands.Context{
		// TODO deprecate this shit
		Context:    context.Background(),
		Online:     true,
		ConfigRoot: repoPath,
		LoadConfig: func(path string) (*config.Config, error) {
			return node.Repo.Config(), nil
		},
		ConstructNode: func() (*core.IpfsNode, error) {
			return node, nil
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/RaveNoX/go-jsonmerge"
	"github.com/RaveNoX/go-jsonmerge/cmd/jsonmerge/options"

	"github.com/RaveNoX/go-jsoncommentstrip"

	"github.com/bmatcuk/doublestar"
	"github.com/spkg/bom"
)

var opts *options.Options

func init() {
	opts = &options.Options{
		Name: filepath.Base(os.Args[0]),
	}
}

func main() {
	opts.ParseOrExit(os.Args[1:])

	patchBuff, err := readJSON(opts.Patch)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Patch load error: %v\n", err)
		os.Exit(2)
	}

	dataFiles, err := getGlobFiles(opts.Globs)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot get data files: %v\n", err)
		os.Exit(3)
	}

	patchFiles(patchBuff, dataFiles, true)
}

func printMergeErrors(file string, info *jsonmerge.Info) {
	for _, err := range info.Errors {
		fmt.Fprintf(os.Stderr, "%v: replace warning: %v\n", file, err)
	}
	fmt.Fprintln(os.Stderr)
}

func printReplaces(file string, info *jsonmerge.Info) {
	for k, v := range info.Replaced {
		vBuff, err := json.Marshal(v)
		if err != nil {
			vBuff = []byte(fmt.Sprintf("<cannot get value as JSON: %v>", err))
		}

		fmt.Printf("  %v = %s\n", k, vBuff)
	}
	fmt.Println()
}

func patchFile(patchBuff []byte, file string, replaces bool) {
	buff, err := readJSON(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: load error: %v\n", file, err)
		return
	}

	result, info, err := jsonmerge.MergeBytesIndent(buff, patchBuff, "", "  ")

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: merge error: %v\n", file, err)
		return
	}

	if len(info.Errors) > 0 {
		printMergeErrors(file, info)
	}

	if !opts.DryRun {
		err = ioutil.WriteFile(file, result, os.ModePerm)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: save error: %v\n", file, err)
		}
	}

	if !opts.Quiet {
		if opts.Verbose {
			fmt.Printf("%v:\n", file)
			if replaces {
				printReplaces(file, info)
			}
		} else {
			fmt.Printf("%v\n", file)
		}
	}
}

func patchFiles(patchBuff []byte, dataFiles []string, replaces bool) {
	for _, file := range dataFiles {
		patchFile(patchBuff, file, replaces)
	}
}

func getGlobFiles(globs []string) (files []string, err error) {
	var globFiles = make(map[string]interface{})
	var matches []string

	for _, glob := range globs {
		matches, err = doublestar.Glob(glob)

		if err != nil {
			err = fmt.Errorf("Glob error \"%v\": %v", glob, err)
			return
		}

		for _, match := range matches {
			globFiles[match] = true
		}
	}

	for file := range globFiles {
		files = append(files, file)
	}

	return
}

func readJSON(filePath string) (buff []byte, err error) {
	file, err := os.Open(filePath)

	if err != nil {
		err = fmt.Errorf("Cannot open file: %v", err)
		return
	}
	defer file.Close()

	bomReader := bom.NewReader(file)
	jsonCommentReader := jsoncommentstrip.NewReader(bomReader)

	buff, err = ioutil.ReadAll(jsonCommentReader)

	if err != nil {
		err = fmt.Errorf("Cannot read JSON: %v", err)
	}
	return
}
<commit_msg>Added sorting for keys and dry-run enabled info<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/RaveNoX/go-jsonmerge"
	"github.com/RaveNoX/go-jsonmerge/cmd/jsonmerge/options"

	"github.com/RaveNoX/go-jsoncommentstrip"

	"sort"

	"github.com/bmatcuk/doublestar"
	"github.com/spkg/bom"
)

var opts *options.Options

func init() {
	opts = &options.Options{
		Name: filepath.Base(os.Args[0]),
	}
}

func main() {
	opts.ParseOrExit(os.Args[1:])

	patchBuff, err := readJSON(opts.Patch)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Patch load error: %v\n", err)
		os.Exit(2)
	}

	dataFiles, err := getGlobFiles(opts.Globs)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot get data files: %v\n", err)
		os.Exit(3)
	}

	if opts.DryRun {
		fmt.Fprintln(os.Stderr, "Dry run: no files will be really patched")
		fmt.Fprintln(os.Stderr)
	}
	patchFiles(patchBuff, dataFiles)
}

func printMergeErrors(file string, info *jsonmerge.Info) {
	for _, err := range info.Errors {
		fmt.Fprintf(os.Stderr, "%v: replace warning: %v\n", file, err)
	}
	fmt.Fprintln(os.Stderr)
}

func printReplaces(file string, info *jsonmerge.Info) {
	var keys []string

	for k := range info.Replaced {
		keys = append(keys, k)
	}

	sort.Strings(keys)

	for _, k := range keys {
		v := info.Replaced[k]
		vBuff, err := json.Marshal(v)
		if err != nil {
			vBuff = []byte(fmt.Sprintf("<cannot get value as JSON: %v>", err))
		}

		fmt.Printf("  %v = %s\n", k, vBuff)
	}
	fmt.Println()
}

func patchFile(patchBuff []byte, file string) {
	buff, err := readJSON(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: load error: %v\n", file, err)
		return
	}

	result, info, err := jsonmerge.MergeBytesIndent(buff, patchBuff, "", "  ")

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: merge error: %v\n", file, err)
		return
	}

	if len(info.Errors) > 0 {
		printMergeErrors(file, info)
	}

	if !opts.DryRun {
		err = ioutil.WriteFile(file, result, os.ModePerm)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: save error: %v\n", file, err)
		}
	}

	if !opts.Quiet {
		if opts.Verbose {
			fmt.Printf("%v:\n", file)
			printReplaces(file, info)
		} else {
			fmt.Printf("%v\n", file)
		}
	}
}

func patchFiles(patchBuff []byte, dataFiles []string) {
	for _, file := range dataFiles {
		patchFile(patchBuff, file)
	}
}

func getGlobFiles(globs []string) (files []string, err error) {
	var globFiles = make(map[string]interface{})
	var matches []string

	for _, glob := range globs {
		matches, err = doublestar.Glob(glob)

		if err != nil {
			err = fmt.Errorf("Glob error \"%v\": %v", glob, err)
			return
		}

		for _, match := range matches {
			globFiles[match] = true
		}
	}

	for file := range globFiles {
		files = append(files, file)
	}

	return
}

func readJSON(filePath string) (buff []byte, err error) {
	file, err := os.Open(filePath)

	if err != nil {
		err = fmt.Errorf("Cannot open file: %v", err)
		return
	}
	defer file.Close()

	bomReader := bom.NewReader(file)
	jsonCommentReader := jsoncommentstrip.NewReader(bomReader)

	buff, err = ioutil.ReadAll(jsonCommentReader)

	if err != nil {
		err = fmt.Errorf("Cannot read JSON: %v", err)
	}
	return
}
<|endoftext|>


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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct{}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHome+"="+config.JujuHome())
	output, err := ps.CombinedOutput()
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestTearDown(c *gc.C) {
	loggo.ResetLoggers()
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// config.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
environments:
    one:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := config.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return fmt.Sprintf("environment configuration has no admin-secret")
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	c.Assert(out, jc.HasSuffix, "ERROR "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* %s\n`, msg)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	c.Assert(out, jc.HasSuffix, "ERROR "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* %s\n`, msg)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-relation", // alias for destroy-relation
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"aws",
	"basics",
	"commands",
	"global-options",
	"glossary",
	"hpcloud",
	"local",
	"openstack",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-config .*",
	"--log-file .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<commit_msg>[r=fwereade] cmd/juju: skip ActualRun tests<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct{}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHome+"="+config.JujuHome())
	output, err := ps.CombinedOutput()
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestTearDown(c *gc.C) {
	loggo.ResetLoggers()
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// config.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
environments:
    one:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := config.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return fmt.Sprintf("environment configuration has no admin-secret")
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	c.Assert(out, jc.HasSuffix, "ERROR "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* %s\n`, msg)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	c.Assert(out, jc.HasSuffix, "ERROR "+msg+"\n")
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* %s\n`, msg)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-relation", // alias for destroy-relation
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"aws",
	"basics",
	"commands",
	"global-options",
	"glossary",
	"hpcloud",
	"local",
	"openstack",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-config .*",
	"--log-file .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer config.SetJujuHome(config.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"os"
	"runtime"

	"github.com/mingzhi/popsimu/pop"
	"gopkg.in/yaml.v2"
)

// Config to read flags and configure file.
type cmdConfig struct {
	// Flags.
	workspace  string
	config     string
	prefix     string
	outdir     string
	ncpu       int
	numGen     int // number of generations.
	numRep     int // number of replicates.
	sampleSize int

	popConfigs []pop.Config
}

// Flags implements command package interface.
func (c *cmdConfig) Flags(fs *flag.FlagSet) *flag.FlagSet {
	fs.StringVar(&c.workspace, "w", "", "workspace")
	fs.StringVar(&c.config, "c", "config.yaml", "configure file in YAML format.")
	fs.StringVar(&c.prefix, "p", "test", "prefix")
	fs.StringVar(&c.outdir, "o", "", "output diretory")
	fs.IntVar(&c.ncpu, "ncpu", runtime.NumCPU(), "number of CPUs for using")
	fs.IntVar(&c.numGen, "g", 1, "number of generations")
	fs.IntVar(&c.numRep, "r", 1, "number of replicates")
	fs.IntVar(&c.sampleSize, "s", 1000, "sample size")
	return fs
}

func (c *cmdConfig) ParsePopConfigs() {
	f, err := os.Open(c.config)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	content, err := ioutil.ReadAll(f)
	if err != nil {
		panic(err)
	}

	if err := yaml.Unmarshal(content, &c.popConfigs); err != nil {
		panic(err)
	}
}
<commit_msg>use json parser<commit_after>package main

import (
	"flag"
	"os"
	"runtime"

	"encoding/json"

	"github.com/mingzhi/popsimu/pop"
)

// Config to read flags and configure file.
type cmdConfig struct {
	// Flags.
	workspace  string
	config     string
	prefix     string
	outdir     string
	ncpu       int
	numGen     int // number of generations.
	numRep     int // number of replicates.
	sampleSize int

	popConfigs []pop.Config
}

// Flags implements command package interface.
func (c *cmdConfig) Flags(fs *flag.FlagSet) *flag.FlagSet {
	fs.StringVar(&c.workspace, "w", "", "workspace")
	fs.StringVar(&c.config, "c", "config.yaml", "configure file in YAML format.")
	fs.StringVar(&c.prefix, "p", "test", "prefix")
	fs.StringVar(&c.outdir, "o", "", "output diretory")
	fs.IntVar(&c.ncpu, "ncpu", runtime.NumCPU(), "number of CPUs for using")
	fs.IntVar(&c.numGen, "g", 1, "number of generations")
	fs.IntVar(&c.numRep, "r", 1, "number of replicates")
	fs.IntVar(&c.sampleSize, "s", 1000, "sample size")
	return fs
}

func (c *cmdConfig) ParsePopConfigs() {
	f, err := os.Open(c.config)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	decorder := json.NewDecoder(f)
	if err := decorder.Decode(&c.popConfigs); err != nil {
		panic(err)
	}
}
<|endoftext|>