<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.
*/

// Package app implements a Server object for running the scheduler.
package app

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	goruntime "runtime"

	"github.com/spf13/cobra"

	"k8s.io/api/core/v1"
	eventsv1beta1 "k8s.io/api/events/v1beta1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfilters "k8s.io/apiserver/pkg/server/filters"
	"k8s.io/apiserver/pkg/server/healthz"
	"k8s.io/apiserver/pkg/server/mux"
	"k8s.io/apiserver/pkg/server/routes"
	"k8s.io/client-go/kubernetes/scheme"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/events"
	"k8s.io/client-go/tools/leaderelection"
	"k8s.io/client-go/tools/record"
	cliflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/cli/globalflag"
	"k8s.io/component-base/configz"
	"k8s.io/component-base/logs"
	"k8s.io/component-base/metrics/legacyregistry"
	"k8s.io/component-base/term"
	"k8s.io/component-base/version"
	"k8s.io/component-base/version/verflag"
	"k8s.io/klog/v2"
	schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
	"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/scheduler"
	kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
	framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
	"k8s.io/kubernetes/pkg/scheduler/metrics"
	"k8s.io/kubernetes/pkg/scheduler/profile"
)

// Option configures a framework.Registry.
type Option func(framework.Registry) error

// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
	opts, err := options.NewOptions()
	if err != nil {
		klog.Fatalf("unable to initialize command options: %v", err)
	}

	cmd := &cobra.Command{
		Use: "kube-scheduler",
		Long: `The Kubernetes scheduler is a control plane process which assigns
Pods to Nodes. The scheduler determines which Nodes are valid placements for
each Pod in the scheduling queue according to constraints and available
resources. The scheduler then ranks each valid Node and binds the Pod to a
suitable Node. Multiple different schedulers may be used within a cluster;
kube-scheduler is the reference implementation.
See [scheduling](https://kubernetes.io/docs/concepts/scheduling/)
for more information about scheduling and the kube-scheduler component.`,
		Run: func(cmd *cobra.Command, args []string) {
			if err := runCommand(cmd, args, opts, registryOptions...); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}
		},
	}
	fs := cmd.Flags()
	namedFlagSets := opts.Flags()
	verflag.AddFlags(namedFlagSets.FlagSet("global"))
	globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
	for _, f := range namedFlagSets.FlagSets {
		fs.AddFlagSet(f)
	}

	usageFmt := "Usage:\n  %s\n"
	cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
	cmd.SetUsageFunc(func(cmd *cobra.Command) error {
		fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine())
		cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols)
		return nil
	})
	cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
		cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
	})
	cmd.MarkFlagFilename("config", "yaml", "yml", "json")

	return cmd
}

// runCommand runs the scheduler.
func runCommand(cmd *cobra.Command, args []string, opts *options.Options, registryOptions ...Option) error {
	verflag.PrintAndExitIfRequested()
	cliflag.PrintFlags(cmd.Flags())

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	cc, sched, err := Setup(ctx, args, opts, registryOptions...)
	if err != nil {
		return err
	}

	if len(opts.WriteConfigTo) > 0 {
		if err := options.WriteConfigFile(opts.WriteConfigTo, &cc.ComponentConfig); err != nil {
			return err
		}
		klog.Infof("Wrote configuration to: %s\n", opts.WriteConfigTo)
		return nil
	}

	return Run(ctx, cc, sched)
}

// Run executes the scheduler based on the given configuration. It only returns on error or when context is done.
func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *scheduler.Scheduler) error {
	// To help debugging, immediately log version
	klog.V(1).Infof("Starting Kubernetes Scheduler version %+v", version.Get())

	// Configz registration.
	if cz, err := configz.New("componentconfig"); err == nil {
		cz.Set(cc.ComponentConfig)
	} else {
		return fmt.Errorf("unable to register configz: %s", err)
	}

	// Prepare the event broadcaster.
	if cc.Broadcaster != nil && cc.EventClient != nil {
		cc.Broadcaster.StartRecordingToSink(ctx.Done())
	}
	if cc.CoreBroadcaster != nil && cc.CoreEventClient != nil {
		cc.CoreBroadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: cc.CoreEventClient.Events("")})
	}
	// Setup healthz checks.
	var checks []healthz.HealthChecker
	if cc.ComponentConfig.LeaderElection.LeaderElect {
		checks = append(checks, cc.LeaderElection.WatchDog)
	}

	// Start up the healthz server.
	if cc.InsecureServing != nil {
		separateMetrics := cc.InsecureMetricsServing != nil
		handler := buildHandlerChain(newHealthzHandler(&cc.ComponentConfig, separateMetrics, checks...), nil, nil)
		if err := cc.InsecureServing.Serve(handler, 0, ctx.Done()); err != nil {
			return fmt.Errorf("failed to start healthz server: %v", err)
		}
	}
	if cc.InsecureMetricsServing != nil {
		handler := buildHandlerChain(newMetricsHandler(&cc.ComponentConfig), nil, nil)
		if err := cc.InsecureMetricsServing.Serve(handler, 0, ctx.Done()); err != nil {
			return fmt.Errorf("failed to start metrics server: %v", err)
		}
	}
	if cc.SecureServing != nil {
		handler := buildHandlerChain(newHealthzHandler(&cc.ComponentConfig, false, checks...), cc.Authentication.Authenticator, cc.Authorization.Authorizer)
		// TODO: handle stoppedCh returned by c.SecureServing.Serve
		if _, err := cc.SecureServing.Serve(handler, 0, ctx.Done()); err != nil {
			// fail early for secure handlers, removing the old error loop from above
			return fmt.Errorf("failed to start secure server: %v", err)
		}
	}

	// Start all informers.
	go cc.PodInformer.Informer().Run(ctx.Done())
	cc.InformerFactory.Start(ctx.Done())

	// Wait for all caches to sync before scheduling.
	cc.InformerFactory.WaitForCacheSync(ctx.Done())

	// If leader election is enabled, runCommand via LeaderElector until done and exit.
	if cc.LeaderElection != nil {
		cc.LeaderElection.Callbacks = leaderelection.LeaderCallbacks{
			OnStartedLeading: sched.Run,
			OnStoppedLeading: func() {
				klog.Fatalf("leaderelection lost")
			},
		}
		leaderElector, err := leaderelection.NewLeaderElector(*cc.LeaderElection)
		if err != nil {
			return fmt.Errorf("couldn't create leader elector: %v", err)
		}

		leaderElector.Run(ctx)

		return fmt.Errorf("lost lease")
	}

	// Leader election is disabled, so runCommand inline until done.
	sched.Run(ctx)
	return fmt.Errorf("finished without leader elect")
}

// buildHandlerChain wraps the given handler with the standard filters.
func buildHandlerChain(handler http.Handler, authn authenticator.Request, authz authorizer.Authorizer) http.Handler {
	requestInfoResolver := &apirequest.RequestInfoFactory{}
	failedHandler := genericapifilters.Unauthorized(legacyscheme.Codecs)

	handler = genericapifilters.WithAuthorization(handler, authz, legacyscheme.Codecs)
	handler = genericapifilters.WithAuthentication(handler, authn, failedHandler, nil)
	handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
	handler = genericapifilters.WithCacheControl(handler)
	handler = genericfilters.WithPanicRecovery(handler)

	return handler
}

func installMetricHandler(pathRecorderMux *mux.PathRecorderMux) {
	configz.InstallHandler(pathRecorderMux)
	//lint:ignore SA1019 See the Metrics Stability Migration KEP
	defaultMetricsHandler := legacyregistry.Handler().ServeHTTP
	pathRecorderMux.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
		if req.Method == "DELETE" {
			metrics.Reset()
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Header().Set("X-Content-Type-Options", "nosniff")
			io.WriteString(w, "metrics reset\n")
			return
		}
		defaultMetricsHandler(w, req)
	})
}

// newMetricsHandler builds a metrics server from the config.
func newMetricsHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration) http.Handler {
	pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler")
	installMetricHandler(pathRecorderMux)
	if config.EnableProfiling {
		routes.Profiling{}.Install(pathRecorderMux)
		if config.EnableContentionProfiling {
			goruntime.SetBlockProfileRate(1)
		}
		routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
	}
	return pathRecorderMux
}

// newHealthzHandler creates a healthz server from the config, and will also
// embed the metrics handler if the healthz and metrics address configurations
// are the same.
func newHealthzHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, separateMetrics bool, checks ...healthz.HealthChecker) http.Handler {
	pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler")
	healthz.InstallHandler(pathRecorderMux, checks...)
	if !separateMetrics {
		installMetricHandler(pathRecorderMux)
	}
	if config.EnableProfiling {
		routes.Profiling{}.Install(pathRecorderMux)
		if config.EnableContentionProfiling {
			goruntime.SetBlockProfileRate(1)
		}
		routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
	}
	return pathRecorderMux
}

func getRecorderFactory(cc *schedulerserverconfig.CompletedConfig) profile.RecorderFactory {
	if _, err := cc.Client.Discovery().ServerResourcesForGroupVersion(eventsv1beta1.SchemeGroupVersion.String()); err == nil {
		cc.Broadcaster = events.NewBroadcaster(&events.EventSinkImpl{Interface: cc.EventClient.Events("")})
		return profile.NewRecorderFactory(cc.Broadcaster)
	}
	return func(name string) events.EventRecorder {
		r := cc.CoreBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: name})
		return record.NewEventRecorderAdapter(r)
	}
}

// WithPlugin creates an Option based on plugin name and factory. Please don't remove this function: it is used to register out-of-tree plugins,
// hence there are no references to it from the kubernetes scheduler code base.
func WithPlugin(name string, factory framework.PluginFactory) Option {
	return func(registry framework.Registry) error {
		return registry.Register(name, factory)
	}
}

// Setup creates a completed config and a scheduler based on the command args and options
func Setup(ctx context.Context, args []string, opts *options.Options, outOfTreeRegistryOptions ...Option) (*schedulerserverconfig.CompletedConfig, *scheduler.Scheduler, error) {
	if len(args) != 0 {
		fmt.Fprint(os.Stderr, "arguments are not supported\n")
	}

	if errs := opts.Validate(); len(errs) > 0 {
		return nil, nil, utilerrors.NewAggregate(errs)
	}

	c, err := opts.Config()
	if err != nil {
		return nil, nil, err
	}

	// Get the completed config
	cc := c.Complete()

	outOfTreeRegistry := make(framework.Registry)
	for _, option := range outOfTreeRegistryOptions {
		if err := option(outOfTreeRegistry); err != nil {
			return nil, nil, err
		}
	}

	recorderFactory := getRecorderFactory(&cc)
	// Create the scheduler.
	sched, err := scheduler.New(cc.Client,
		cc.InformerFactory,
		cc.PodInformer,
		recorderFactory,
		ctx.Done(),
		scheduler.WithProfiles(cc.ComponentConfig.Profiles...),
		scheduler.WithAlgorithmSource(cc.ComponentConfig.AlgorithmSource),
		scheduler.WithPreemptionDisabled(cc.ComponentConfig.DisablePreemption),
		scheduler.WithPercentageOfNodesToScore(cc.ComponentConfig.PercentageOfNodesToScore),
		scheduler.WithBindTimeoutSeconds(cc.ComponentConfig.BindTimeoutSeconds),
		scheduler.WithFrameworkOutOfTreeRegistry(outOfTreeRegistry),
		scheduler.WithPodMaxBackoffSeconds(cc.ComponentConfig.PodMaxBackoffSeconds),
		scheduler.WithPodInitialBackoffSeconds(cc.ComponentConfig.PodInitialBackoffSeconds),
		scheduler.WithExtenders(cc.ComponentConfig.Extenders...),
	)
	if err != nil {
		return nil, nil, err
	}

	return &cc, sched, nil
}
<commit_msg>fix,404 link in kube-scheduler command usage description<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.
*/

// Package app implements a Server object for running the scheduler.
package app

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	goruntime "runtime"

	"github.com/spf13/cobra"

	"k8s.io/api/core/v1"
	eventsv1beta1 "k8s.io/api/events/v1beta1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apiserver/pkg/authentication/authenticator"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfilters "k8s.io/apiserver/pkg/server/filters"
	"k8s.io/apiserver/pkg/server/healthz"
	"k8s.io/apiserver/pkg/server/mux"
	"k8s.io/apiserver/pkg/server/routes"
	"k8s.io/client-go/kubernetes/scheme"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/events"
	"k8s.io/client-go/tools/leaderelection"
	"k8s.io/client-go/tools/record"
	cliflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/cli/globalflag"
	"k8s.io/component-base/configz"
	"k8s.io/component-base/logs"
	"k8s.io/component-base/metrics/legacyregistry"
	"k8s.io/component-base/term"
	"k8s.io/component-base/version"
	"k8s.io/component-base/version/verflag"
	"k8s.io/klog/v2"
	schedulerserverconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
	"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/scheduler"
	kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
	framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
	"k8s.io/kubernetes/pkg/scheduler/metrics"
	"k8s.io/kubernetes/pkg/scheduler/profile"
)

// Option configures a framework.Registry.
type Option func(framework.Registry) error

// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
	opts, err := options.NewOptions()
	if err != nil {
		klog.Fatalf("unable to initialize command options: %v", err)
	}

	cmd := &cobra.Command{
		Use: "kube-scheduler",
		Long: `The Kubernetes scheduler is a control plane process which assigns
Pods to Nodes. The scheduler determines which Nodes are valid placements for
each Pod in the scheduling queue according to constraints and available
resources. The scheduler then ranks each valid Node and binds the Pod to a
suitable Node. Multiple different schedulers may be used within a cluster;
kube-scheduler is the reference implementation.
See [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/)
for more information about scheduling and the kube-scheduler component.`,
		Run: func(cmd *cobra.Command, args []string) {
			if err := runCommand(cmd, args, opts, registryOptions...); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}
		},
	}
	fs := cmd.Flags()
	namedFlagSets := opts.Flags()
	verflag.AddFlags(namedFlagSets.FlagSet("global"))
	globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
	for _, f := range namedFlagSets.FlagSets {
		fs.AddFlagSet(f)
	}

	usageFmt := "Usage:\n  %s\n"
	cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
	cmd.SetUsageFunc(func(cmd *cobra.Command) error {
		fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine())
		cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols)
		return nil
	})
	cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
		cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
	})
	cmd.MarkFlagFilename("config", "yaml", "yml", "json")

	return cmd
}

// runCommand runs the scheduler.
func runCommand(cmd *cobra.Command, args []string, opts *options.Options, registryOptions ...Option) error {
	verflag.PrintAndExitIfRequested()
	cliflag.PrintFlags(cmd.Flags())

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	cc, sched, err := Setup(ctx, args, opts, registryOptions...)
	if err != nil {
		return err
	}

	if len(opts.WriteConfigTo) > 0 {
		if err := options.WriteConfigFile(opts.WriteConfigTo, &cc.ComponentConfig); err != nil {
			return err
		}
		klog.Infof("Wrote configuration to: %s\n", opts.WriteConfigTo)
		return nil
	}

	return Run(ctx, cc, sched)
}

// Run executes the scheduler based on the given configuration. It only returns on error or when context is done.
func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *scheduler.Scheduler) error {
	// To help debugging, immediately log version
	klog.V(1).Infof("Starting Kubernetes Scheduler version %+v", version.Get())

	// Configz registration.
	if cz, err := configz.New("componentconfig"); err == nil {
		cz.Set(cc.ComponentConfig)
	} else {
		return fmt.Errorf("unable to register configz: %s", err)
	}

	// Prepare the event broadcaster.
	if cc.Broadcaster != nil && cc.EventClient != nil {
		cc.Broadcaster.StartRecordingToSink(ctx.Done())
	}
	if cc.CoreBroadcaster != nil && cc.CoreEventClient != nil {
		cc.CoreBroadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: cc.CoreEventClient.Events("")})
	}
	// Setup healthz checks.
	var checks []healthz.HealthChecker
	if cc.ComponentConfig.LeaderElection.LeaderElect {
		checks = append(checks, cc.LeaderElection.WatchDog)
	}

	// Start up the healthz server.
	if cc.InsecureServing != nil {
		separateMetrics := cc.InsecureMetricsServing != nil
		handler := buildHandlerChain(newHealthzHandler(&cc.ComponentConfig, separateMetrics, checks...), nil, nil)
		if err := cc.InsecureServing.Serve(handler, 0, ctx.Done()); err != nil {
			return fmt.Errorf("failed to start healthz server: %v", err)
		}
	}
	if cc.InsecureMetricsServing != nil {
		handler := buildHandlerChain(newMetricsHandler(&cc.ComponentConfig), nil, nil)
		if err := cc.InsecureMetricsServing.Serve(handler, 0, ctx.Done()); err != nil {
			return fmt.Errorf("failed to start metrics server: %v", err)
		}
	}
	if cc.SecureServing != nil {
		handler := buildHandlerChain(newHealthzHandler(&cc.ComponentConfig, false, checks...), cc.Authentication.Authenticator, cc.Authorization.Authorizer)
		// TODO: handle stoppedCh returned by c.SecureServing.Serve
		if _, err := cc.SecureServing.Serve(handler, 0, ctx.Done()); err != nil {
			// fail early for secure handlers, removing the old error loop from above
			return fmt.Errorf("failed to start secure server: %v", err)
		}
	}

	// Start all informers.
	go cc.PodInformer.Informer().Run(ctx.Done())
	cc.InformerFactory.Start(ctx.Done())

	// Wait for all caches to sync before scheduling.
	cc.InformerFactory.WaitForCacheSync(ctx.Done())

	// If leader election is enabled, runCommand via LeaderElector until done and exit.
	if cc.LeaderElection != nil {
		cc.LeaderElection.Callbacks = leaderelection.LeaderCallbacks{
			OnStartedLeading: sched.Run,
			OnStoppedLeading: func() {
				klog.Fatalf("leaderelection lost")
			},
		}
		leaderElector, err := leaderelection.NewLeaderElector(*cc.LeaderElection)
		if err != nil {
			return fmt.Errorf("couldn't create leader elector: %v", err)
		}

		leaderElector.Run(ctx)

		return fmt.Errorf("lost lease")
	}

	// Leader election is disabled, so runCommand inline until done.
	sched.Run(ctx)
	return fmt.Errorf("finished without leader elect")
}

// buildHandlerChain wraps the given handler with the standard filters.
func buildHandlerChain(handler http.Handler, authn authenticator.Request, authz authorizer.Authorizer) http.Handler {
	requestInfoResolver := &apirequest.RequestInfoFactory{}
	failedHandler := genericapifilters.Unauthorized(legacyscheme.Codecs)

	handler = genericapifilters.WithAuthorization(handler, authz, legacyscheme.Codecs)
	handler = genericapifilters.WithAuthentication(handler, authn, failedHandler, nil)
	handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
	handler = genericapifilters.WithCacheControl(handler)
	handler = genericfilters.WithPanicRecovery(handler)

	return handler
}

func installMetricHandler(pathRecorderMux *mux.PathRecorderMux) {
	configz.InstallHandler(pathRecorderMux)
	//lint:ignore SA1019 See the Metrics Stability Migration KEP
	defaultMetricsHandler := legacyregistry.Handler().ServeHTTP
	pathRecorderMux.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
		if req.Method == "DELETE" {
			metrics.Reset()
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Header().Set("X-Content-Type-Options", "nosniff")
			io.WriteString(w, "metrics reset\n")
			return
		}
		defaultMetricsHandler(w, req)
	})
}

// newMetricsHandler builds a metrics server from the config.
func newMetricsHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration) http.Handler {
	pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler")
	installMetricHandler(pathRecorderMux)
	if config.EnableProfiling {
		routes.Profiling{}.Install(pathRecorderMux)
		if config.EnableContentionProfiling {
			goruntime.SetBlockProfileRate(1)
		}
		routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
	}
	return pathRecorderMux
}

// newHealthzHandler creates a healthz server from the config, and will also
// embed the metrics handler if the healthz and metrics address configurations
// are the same.
func newHealthzHandler(config *kubeschedulerconfig.KubeSchedulerConfiguration, separateMetrics bool, checks ...healthz.HealthChecker) http.Handler {
	pathRecorderMux := mux.NewPathRecorderMux("kube-scheduler")
	healthz.InstallHandler(pathRecorderMux, checks...)
	if !separateMetrics {
		installMetricHandler(pathRecorderMux)
	}
	if config.EnableProfiling {
		routes.Profiling{}.Install(pathRecorderMux)
		if config.EnableContentionProfiling {
			goruntime.SetBlockProfileRate(1)
		}
		routes.DebugFlags{}.Install(pathRecorderMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
	}
	return pathRecorderMux
}

func getRecorderFactory(cc *schedulerserverconfig.CompletedConfig) profile.RecorderFactory {
	if _, err := cc.Client.Discovery().ServerResourcesForGroupVersion(eventsv1beta1.SchemeGroupVersion.String()); err == nil {
		cc.Broadcaster = events.NewBroadcaster(&events.EventSinkImpl{Interface: cc.EventClient.Events("")})
		return profile.NewRecorderFactory(cc.Broadcaster)
	}
	return func(name string) events.EventRecorder {
		r := cc.CoreBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: name})
		return record.NewEventRecorderAdapter(r)
	}
}

// WithPlugin creates an Option based on plugin name and factory. Please don't remove this function: it is used to register out-of-tree plugins,
// hence there are no references to it from the kubernetes scheduler code base.
func WithPlugin(name string, factory framework.PluginFactory) Option {
	return func(registry framework.Registry) error {
		return registry.Register(name, factory)
	}
}

// Setup creates a completed config and a scheduler based on the command args and options
func Setup(ctx context.Context, args []string, opts *options.Options, outOfTreeRegistryOptions ...Option) (*schedulerserverconfig.CompletedConfig, *scheduler.Scheduler, error) {
	if len(args) != 0 {
		fmt.Fprint(os.Stderr, "arguments are not supported\n")
	}

	if errs := opts.Validate(); len(errs) > 0 {
		return nil, nil, utilerrors.NewAggregate(errs)
	}

	c, err := opts.Config()
	if err != nil {
		return nil, nil, err
	}

	// Get the completed config
	cc := c.Complete()

	outOfTreeRegistry := make(framework.Registry)
	for _, option := range outOfTreeRegistryOptions {
		if err := option(outOfTreeRegistry); err != nil {
			return nil, nil, err
		}
	}

	recorderFactory := getRecorderFactory(&cc)
	// Create the scheduler.
	sched, err := scheduler.New(cc.Client,
		cc.InformerFactory,
		cc.PodInformer,
		recorderFactory,
		ctx.Done(),
		scheduler.WithProfiles(cc.ComponentConfig.Profiles...),
		scheduler.WithAlgorithmSource(cc.ComponentConfig.AlgorithmSource),
		scheduler.WithPreemptionDisabled(cc.ComponentConfig.DisablePreemption),
		scheduler.WithPercentageOfNodesToScore(cc.ComponentConfig.PercentageOfNodesToScore),
		scheduler.WithBindTimeoutSeconds(cc.ComponentConfig.BindTimeoutSeconds),
		scheduler.WithFrameworkOutOfTreeRegistry(outOfTreeRegistry),
		scheduler.WithPodMaxBackoffSeconds(cc.ComponentConfig.PodMaxBackoffSeconds),
		scheduler.WithPodInitialBackoffSeconds(cc.ComponentConfig.PodInitialBackoffSeconds),
		scheduler.WithExtenders(cc.ComponentConfig.Extenders...),
	)
	if err != nil {
		return nil, nil, err
	}

	return &cc, sched, nil
}
<|endoftext|>


<commit_before>package apiendpoints

import (
	"fmt"
	"strconv"

	"github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1"
	"github.com/google/go-querystring/query"
)

type Endpoints []Endpoint

type Endpoint struct {
	APICategoryIds             []int                 `json:"apiCategoryIds,omitempty"`
	APIEndPointHosts           []string              `json:"apiEndPointHosts"`
	APIEndPointID              int                   `json:"apiEndPointId,omitempty"`
	APIEndPointLocked          bool                  `json:"apiEndPointLocked,omitempty"`
	APIEndPointName            string                `json:"apiEndPointName"`
	APIEndPointScheme          string                `json:"apiEndPointScheme,omitempty"`
	APIResourceBaseInfo        []*ResourceBaseInfo   `json:"apiResourceBaseInfo,omitempty"`
	BasePath                   string                `json:"basePath,omitempty"`
	ClonedFromVersion          *int                  `json:"clonedFromVersion,omitempty"`
	ConsumeType                string                `json:"consumeType,omitempty"`
	ContractID                 string                `json:"contractId,omitempty"`
	CreateDate                 string                `json:"createDate,omitempty"`
	CreatedBy                  string                `json:"createdBy,omitempty"`
	Description                string                `json:"description,omitempty"`
	GroupID                    int                   `json:"groupId,omitempty"`
	ProductionVersion          *VersionSummary       `json:"productionVersion,omitempty"`
	ProductionStatus           string                `json:"productionStatus,omitempty"`
	ProtectedByAPIKey          bool                  `json:"protectedByApiKey,omitempty"`
	StagingStatus              string                `json:"stagingStatus,omitempty"`
	StagingVersion             *VersionSummary       `json:"stagingVersion,omitempty"`
	UpdateDate                 string                `json:"updateDate,omitempty"`
	UpdatedBy                  string                `json:"updatedBy,omitempty"`
	VersionNumber              int                   `json:"versionNumber,omitempty"`
	SecurityScheme             *SecurityScheme       `json:"securityScheme,omitempty"`
	AkamaiSecurityRestrictions *SecurityRestrictions `json:"akamaiSecurityRestrictions,omitempty"`
	APIResources               *Resources            `json:"apiResources,omitempty"`
}

type SecurityScheme struct {
	SecuritySchemeType   string `json:"securitySchemeType,omitempty"`
	SecuritySchemeDetail struct {
		APIKeyLocation string `json:"apiKeyLocation,omitempty"`
		APIKeyName     string `json:"apiKeyName,omitempty"`
	} `json:"securitySchemeDetail,omitempty"`
}

type SecurityRestrictions struct {
	MaxJsonxmlElement       int `json:"MAX_JSONXML_ELEMENT,omitempty"`
	MaxElementNameLength    int `json:"MAX_ELEMENT_NAME_LENGTH,omitempty"`
	MaxDocDepth             int `json:"MAX_DOC_DEPTH,omitempty"`
	PositiveSecurityEnabled int `json:"POSITIVE_SECURITY_ENABLED,omitempty"`
	MaxStringLength         int `json:"MAX_STRING_LENGTH,omitempty"`
	MaxBodySize             int `json:"MAX_BODY_SIZE,omitempty"`
	MaxIntegerValue         int `json:"MAX_INTEGER_VALUE,omitempty"`
}

type CreateEndpointOptions struct {
	ContractId string   `json:"contractId,omitempty"`
	GroupId    int      `json:"groupId,omitempty"`
	Name       string   `json:"apiEndPointName,omitempty"`
	BasePath   string   `json:"basePath,omitempty"`
	Hostnames  []string `json:"apiEndPointHosts,omitempty"`
}

func CreateEndpoint(options *CreateEndpointOptions) (*Endpoint, error) {
	req, err := client.NewJSONRequest(
		Config,
		"POST",
		"/api-definitions/v2/endpoints",
		options,
	)

	return call(req, err)
}

type CreateEndpointFromFileOptions struct {
	File       string
	Format     string
	ContractId string
	GroupId    int
}

func CreateEndpointFromFile(options *CreateEndpointFromFileOptions) (*Endpoint, error) {
	req, err := client.NewMultiPartFormDataRequest(
		Config,
		"/api-definitions/v2/endpoints/files",
		options.File,
		map[string]string{
			"contractId":       options.ContractId,
			"groupId":          strconv.Itoa(options.GroupId),
			"importFileFormat": options.Format,
		},
	)

	return call(req, err)
}

type UpdateEndpointFromFileOptions struct {
	EndpointId int
	Version    int
	File       string
	Format     string
}

func UpdateEndpointFromFile(options *UpdateEndpointFromFileOptions) (*Endpoint, error) {
	url := fmt.Sprintf(
		"/api-definitions/v2/endpoints/%d/versions/%d/file",
		options.EndpointId,
		options.Version,
	)

	req, err := client.NewMultiPartFormDataRequest(
		Config,
		url,
		options.File,
		map[string]string{
			"importFileFormat": options.Format,
		},
	)

	return call(req, err)
}

type ListEndpointOptions struct {
	ContractId        string `url:"contractId,omitempty"`
	GroupId           int    `url:"groupId,omitempty"`
	Category          string `url:"category,omitempty"`
	Contains          string `url:"contains,omitempty"`
	Page              int    `url:"page,omitempty"`
	PageSize          int    `url:"pageSize,omitempty"`
	Show              string `url:show,omitempty`
	SortBy            string `url:"sortBy,omitempty"`
	SortOrder         string `url:"sortOrder,omitempty"`
	VersionPreference string `url:"versionPreference,omitempty"`
}

type EndpointList struct {
	APIEndPoints Endpoints `json:"apiEndPoints"`
	Links        Links     `json:"links"`
	Page         int       `json:"page"`
	PageSize     int       `json:"pageSize"`
	TotalSize    int       `json:"totalSize"`
}

func (list *EndpointList) ListEndpoints(options *ListEndpointOptions) error {
	q, err := query.Values(options)
	if err != nil {
		return err
	}

	url := fmt.Sprintf(
		"/api-definitions/v2/endpoints?%s",
		q.Encode(),
	)

	req, err := client.NewJSONRequest(Config, "GET", url, nil)
	if err != nil {
		return err
	}

	res, err := client.Do(Config, req)
	if err != nil {
		return err
	}

	if client.IsError(res) {
		return client.NewAPIError(res)
	}

	if err = client.BodyJSON(res, list); err != nil {
		return err
	}

	return nil
}

func RemoveEndpoint(endpointId int) (*Endpoint, error) {
	req, err := client.NewJSONRequest(
		Config,
		"DELETE",
		fmt.Sprintf(
			"/api-definitions/v2/endpoints/%d",
			endpointId,
		),
		nil,
	)

	if err != nil {
		return nil, err
	}

	res, err := client.Do(Config, req)

	if client.IsError(res) {
		return nil, client.NewAPIError(res)
	}

	rep := &Endpoint{}
	return rep, nil
}
<commit_msg>Make this a separate type so it's cleaner when using these types<commit_after>package apiendpoints

import (
	"fmt"
	"strconv"

	"github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1"
	"github.com/google/go-querystring/query"
)

type Endpoints []Endpoint

type Endpoint struct {
	APICategoryIds             []int                 `json:"apiCategoryIds,omitempty"`
	APIEndPointHosts           []string              `json:"apiEndPointHosts"`
	APIEndPointID              int                   `json:"apiEndPointId,omitempty"`
	APIEndPointLocked          bool                  `json:"apiEndPointLocked,omitempty"`
	APIEndPointName            string                `json:"apiEndPointName"`
	APIEndPointScheme          string                `json:"apiEndPointScheme,omitempty"`
	APIResourceBaseInfo        []*ResourceBaseInfo   `json:"apiResourceBaseInfo,omitempty"`
	BasePath                   string                `json:"basePath,omitempty"`
	ClonedFromVersion          *int                  `json:"clonedFromVersion,omitempty"`
	ConsumeType                string                `json:"consumeType,omitempty"`
	ContractID                 string                `json:"contractId,omitempty"`
	CreateDate                 string                `json:"createDate,omitempty"`
	CreatedBy                  string                `json:"createdBy,omitempty"`
	Description                string                `json:"description,omitempty"`
	GroupID                    int                   `json:"groupId,omitempty"`
	ProductionVersion          *VersionSummary       `json:"productionVersion,omitempty"`
	ProductionStatus           string                `json:"productionStatus,omitempty"`
	ProtectedByAPIKey          bool                  `json:"protectedByApiKey,omitempty"`
	StagingStatus              string                `json:"stagingStatus,omitempty"`
	StagingVersion             *VersionSummary       `json:"stagingVersion,omitempty"`
	UpdateDate                 string                `json:"updateDate,omitempty"`
	UpdatedBy                  string                `json:"updatedBy,omitempty"`
	VersionNumber              int                   `json:"versionNumber,omitempty"`
	SecurityScheme             *SecurityScheme       `json:"securityScheme,omitempty"`
	AkamaiSecurityRestrictions *SecurityRestrictions `json:"akamaiSecurityRestrictions,omitempty"`
	APIResources               *Resources            `json:"apiResources,omitempty"`
}

type SecurityScheme struct {
	SecuritySchemeType   string                `json:"securitySchemeType,omitempty"`
	SecuritySchemeDetail *SecuritySchemeDetail `json:"securitySchemeDetail,omitempty"`
}

type SecuritySchemeDetail struct {
	APIKeyLocation string `json:"apiKeyLocation,omitempty"`
	APIKeyName     string `json:"apiKeyName,omitempty"`
}

type SecurityRestrictions struct {
	MaxJsonxmlElement       int `json:"MAX_JSONXML_ELEMENT,omitempty"`
	MaxElementNameLength    int `json:"MAX_ELEMENT_NAME_LENGTH,omitempty"`
	MaxDocDepth             int `json:"MAX_DOC_DEPTH,omitempty"`
	PositiveSecurityEnabled int `json:"POSITIVE_SECURITY_ENABLED,omitempty"`
	MaxStringLength         int `json:"MAX_STRING_LENGTH,omitempty"`
	MaxBodySize             int `json:"MAX_BODY_SIZE,omitempty"`
	MaxIntegerValue         int `json:"MAX_INTEGER_VALUE,omitempty"`
}

type CreateEndpointOptions struct {
	ContractId string   `json:"contractId,omitempty"`
	GroupId    int      `json:"groupId,omitempty"`
	Name       string   `json:"apiEndPointName,omitempty"`
	BasePath   string   `json:"basePath,omitempty"`
	Hostnames  []string `json:"apiEndPointHosts,omitempty"`
}

func CreateEndpoint(options *CreateEndpointOptions) (*Endpoint, error) {
	req, err := client.NewJSONRequest(
		Config,
		"POST",
		"/api-definitions/v2/endpoints",
		options,
	)

	return call(req, err)
}

type CreateEndpointFromFileOptions struct {
	File       string
	Format     string
	ContractId string
	GroupId    int
}

func CreateEndpointFromFile(options *CreateEndpointFromFileOptions) (*Endpoint, error) {
	req, err := client.NewMultiPartFormDataRequest(
		Config,
		"/api-definitions/v2/endpoints/files",
		options.File,
		map[string]string{
			"contractId":       options.ContractId,
			"groupId":          strconv.Itoa(options.GroupId),
			"importFileFormat": options.Format,
		},
	)

	return call(req, err)
}

type UpdateEndpointFromFileOptions struct {
	EndpointId int
	Version    int
	File       string
	Format     string
}

func UpdateEndpointFromFile(options *UpdateEndpointFromFileOptions) (*Endpoint, error) {
	url := fmt.Sprintf(
		"/api-definitions/v2/endpoints/%d/versions/%d/file",
		options.EndpointId,
		options.Version,
	)

	req, err := client.NewMultiPartFormDataRequest(
		Config,
		url,
		options.File,
		map[string]string{
			"importFileFormat": options.Format,
		},
	)

	return call(req, err)
}

type ListEndpointOptions struct {
	ContractId        string `url:"contractId,omitempty"`
	GroupId           int    `url:"groupId,omitempty"`
	Category          string `url:"category,omitempty"`
	Contains          string `url:"contains,omitempty"`
	Page              int    `url:"page,omitempty"`
	PageSize          int    `url:"pageSize,omitempty"`
	Show              string `url:show,omitempty`
	SortBy            string `url:"sortBy,omitempty"`
	SortOrder         string `url:"sortOrder,omitempty"`
	VersionPreference string `url:"versionPreference,omitempty"`
}

type EndpointList struct {
	APIEndPoints Endpoints `json:"apiEndPoints"`
	Links        Links     `json:"links"`
	Page         int       `json:"page"`
	PageSize     int       `json:"pageSize"`
	TotalSize    int       `json:"totalSize"`
}

func (list *EndpointList) ListEndpoints(options *ListEndpointOptions) error {
	q, err := query.Values(options)
	if err != nil {
		return err
	}

	url := fmt.Sprintf(
		"/api-definitions/v2/endpoints?%s",
		q.Encode(),
	)

	req, err := client.NewJSONRequest(Config, "GET", url, nil)
	if err != nil {
		return err
	}

	res, err := client.Do(Config, req)
	if err != nil {
		return err
	}

	if client.IsError(res) {
		return client.NewAPIError(res)
	}

	if err = client.BodyJSON(res, list); err != nil {
		return err
	}

	return nil
}

func RemoveEndpoint(endpointId int) (*Endpoint, error) {
	req, err := client.NewJSONRequest(
		Config,
		"DELETE",
		fmt.Sprintf(
			"/api-definitions/v2/endpoints/%d",
			endpointId,
		),
		nil,
	)

	if err != nil {
		return nil, err
	}

	res, err := client.Do(Config, req)

	if client.IsError(res) {
		return nil, client.NewAPIError(res)
	}

	rep := &Endpoint{}
	return rep, nil
}
<|endoftext|>


<commit_before>package redis

import (
	"encoding/json"
	"strconv"

	"gopkg.in/redis.v4"

	"gopkg.in/oauth2.v3"
	"gopkg.in/oauth2.v3/models"
)

// DefaultIncrKey The name of the key stored on the ID
const DefaultIncrKey = "oauth2_incr"

// NewTokenStore Create a token store instance based on redis
func NewTokenStore(cfg *Config) (ts oauth2.TokenStore, err error) {
	opt := &redis.Options{
		Network:      cfg.Network,
		Addr:         cfg.Addr,
		Password:     cfg.Password,
		DB:           cfg.DB,
		MaxRetries:   cfg.MaxRetries,
		DialTimeout:  cfg.DialTimeout,
		ReadTimeout:  cfg.ReadTimeout,
		WriteTimeout: cfg.WriteTimeout,
		PoolSize:     cfg.PoolSize,
		PoolTimeout:  cfg.PoolTimeout,
	}
	cli := redis.NewClient(opt)
	if verr := cli.Ping().Err(); verr != nil {
		err = verr
		return
	}
	ts = &TokenStore{cli: cli}
	return
}

// TokenStore redis token store
type TokenStore struct {
	cli *redis.Client
}

func (rs *TokenStore) getBasicID(id int64, info oauth2.TokenInfo) string {
	return "oauth2_" + info.GetClientID() + "_" + strconv.FormatInt(id, 10)
}

// Create Create and store the new token information
func (rs *TokenStore) Create(info oauth2.TokenInfo) (err error) {
	jv, err := json.Marshal(info)
	if err != nil {
		return
	}
	id, err := rs.cli.Incr(DefaultIncrKey).Result()
	if err != nil {
		return
	}
	pipe := rs.cli.Pipeline()
	basicID := rs.getBasicID(id, info)
	aexp := info.GetAccessExpiresIn()
	rexp := aexp

	if refresh := info.GetRefresh(); refresh != "" {
		rexp = info.GetRefreshExpiresIn()
		ttl := rs.cli.TTL(refresh)
		if verr := ttl.Err(); verr != nil {
			err = verr
			return
		}
		if v := ttl.Val(); v.Seconds() > 0 {
			rexp = v
		}
		if aexp.Seconds() > rexp.Seconds() {
			aexp = rexp
		}
		pipe.Set(refresh, basicID, rexp)
	}
	pipe.Set(info.GetAccess(), basicID, aexp)
	pipe.Set(basicID, jv, rexp)

	if _, verr := pipe.Exec(); verr != nil {
		err = verr
	}
	return
}

// remove
func (rs *TokenStore) remove(key string) (err error) {
	_, verr := rs.cli.Del(key).Result()
	if verr != redis.Nil {
		err = verr
	}
	return
}

// RemoveByAccess Use the access token to delete the token information
func (rs *TokenStore) RemoveByAccess(access string) (err error) {
	err = rs.remove(access)
	return
}

// RemoveByRefresh Use the refresh token to delete the token information
func (rs *TokenStore) RemoveByRefresh(refresh string) (err error) {
	err = rs.remove(refresh)
	return
}

// get
func (rs *TokenStore) get(token string) (ti oauth2.TokenInfo, err error) {
	tv, verr := rs.cli.Get(token).Result()
	if verr != nil {
		if verr == redis.Nil {
			return
		}
		err = verr
		return
	}
	result := rs.cli.Get(tv)
	if verr := result.Err(); verr != nil {
		if verr == redis.Nil {
			return
		}
		err = verr
		return
	}
	iv, err := result.Bytes()
	if err != nil {
		return
	}
	var tm models.Token
	if verr := json.Unmarshal(iv, &tm); verr != nil {
		err = verr
		return
	}
	ti = &tm
	return
}

// GetByAccess Use the access token for token information data
func (rs *TokenStore) GetByAccess(access string) (ti oauth2.TokenInfo, err error) {
	ti, err = rs.get(access)
	return
}

// GetByRefresh Use the refresh token for token information data
func (rs *TokenStore) GetByRefresh(refresh string) (ti oauth2.TokenInfo, err error) {
	ti, err = rs.get(refresh)
	return
}
<commit_msg>Token storage optimization<commit_after>package redis

import (
	"encoding/json"
	"time"

	"github.com/satori/go.uuid"
	"gopkg.in/redis.v4"

	"gopkg.in/oauth2.v3"
	"gopkg.in/oauth2.v3/models"
)

// NewTokenStore Create a token store instance based on redis
func NewTokenStore(cfg *Config) (ts oauth2.TokenStore, err error) {
	opt := &redis.Options{
		Network:      cfg.Network,
		Addr:         cfg.Addr,
		Password:     cfg.Password,
		DB:           cfg.DB,
		MaxRetries:   cfg.MaxRetries,
		DialTimeout:  cfg.DialTimeout,
		ReadTimeout:  cfg.ReadTimeout,
		WriteTimeout: cfg.WriteTimeout,
		PoolSize:     cfg.PoolSize,
		PoolTimeout:  cfg.PoolTimeout,
	}
	cli := redis.NewClient(opt)
	if verr := cli.Ping().Err(); verr != nil {
		err = verr
		return
	}
	ts = &TokenStore{cli: cli}
	return
}

// TokenStore redis token store
type TokenStore struct {
	cli *redis.Client
}

// Create Create and store the new token information
func (rs *TokenStore) Create(info oauth2.TokenInfo) (err error) {
	ct := time.Now()
	jv, err := json.Marshal(info)
	if err != nil {
		return
	}
	pipe := rs.cli.Pipeline()
	basicID := uuid.NewV4().String()
	aexp := info.GetAccessExpiresIn()
	rexp := aexp

	if refresh := info.GetRefresh(); refresh != "" {
		rexp = info.GetRefreshCreateAt().Add(info.GetRefreshExpiresIn()).Sub(ct)
		if aexp.Seconds() > rexp.Seconds() {
			aexp = rexp
		}
		pipe.Set(refresh, basicID, rexp)
	}
	pipe.Set(info.GetAccess(), basicID, aexp)
	pipe.Set(basicID, jv, rexp)

	if _, verr := pipe.Exec(); verr != nil {
		err = verr
	}
	return
}

// remove
func (rs *TokenStore) remove(key string) (err error) {
	_, verr := rs.cli.Del(key).Result()
	if verr != redis.Nil {
		err = verr
	}
	return
}

// RemoveByAccess Use the access token to delete the token information
func (rs *TokenStore) RemoveByAccess(access string) (err error) {
	err = rs.remove(access)
	return
}

// RemoveByRefresh Use the refresh token to delete the token information
func (rs *TokenStore) RemoveByRefresh(refresh string) (err error) {
	err = rs.remove(refresh)
	return
}

// get
func (rs *TokenStore) get(token string) (ti oauth2.TokenInfo, err error) {
	tv, verr := rs.cli.Get(token).Result()
	if verr != nil {
		if verr == redis.Nil {
			return
		}
		err = verr
		return
	}
	result := rs.cli.Get(tv)
	if verr := result.Err(); verr != nil {
		if verr == redis.Nil {
			return
		}
		err = verr
		return
	}
	iv, err := result.Bytes()
	if err != nil {
		return
	}
	var tm models.Token
	if verr := json.Unmarshal(iv, &tm); verr != nil {
		err = verr
		return
	}
	ti = &tm
	return
}

// GetByAccess Use the access token for token information data
func (rs *TokenStore) GetByAccess(access string) (ti oauth2.TokenInfo, err error) {
	ti, err = rs.get(access)
	return
}

// GetByRefresh Use the refresh token for token information data
func (rs *TokenStore) GetByRefresh(refresh string) (ti oauth2.TokenInfo, err error) {
	ti, err = rs.get(refresh)
	return
}
<|endoftext|>


<commit_before>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * template_infer.go
 *
 *  Created on Jun 06, 2018
 *      Author Massimiliano Ghilardi
 */

package fast

import (
	"go/ast"
	"go/token"
	r "reflect"

	xr "github.com/cosmos72/gomacro/xreflect"
)

type inferredType struct {
	Type  xr.Type
	Exact bool
}

// type inference on template functions
type inferFuncType struct {
	comp     *Comp
	tfun     *TemplateFunc
	funcname string
	inferred map[string]inferredType
	patterns []ast.Expr
	targs    []xr.Type
	call     *ast.CallExpr // for error messages
}

func (inf *inferFuncType) String() string {
	return inf.tfun.Signature(inf.funcname)
}

func (c *Comp) inferTemplateFunc(call *ast.CallExpr, fun *Expr, args []*Expr) *Expr {
	tfun, ok := fun.Value.(*TemplateFunc)
	if !ok {
		c.Errorf("internal error: Comp.inferTemplateFunc() invoked on non-template function %v: %v", fun.Type, call.Fun)
	}
	var upc *Comp
	var funcname string
	{
		ident, ok := call.Fun.(*ast.Ident)
		if !ok {
			c.Errorf("unimplemented type inference on non-name template function %v: %v", call.Fun, call)
		}
		if fun.Sym == nil {
			c.Errorf("unimplemented type inference on non-symbol template function %v %#v: %v", call.Fun, fun, call)
		}
		// find the scope where fun is declared
		funcname = ident.Name
		fbind := &fun.Sym.Bind
		for upc = c; upc != nil; upc = upc.Outer {
			if bind, ok := upc.Binds[funcname]; ok && bind.Name == fbind.Name && bind.Desc == fbind.Desc && bind.Type.IdenticalTo(fbind.Type) {
				break
			}
		}
	}
	if upc == nil {
		c.Errorf("internal error: Comp.inferTemplateFunc() failed to determine the scope containing template function declaration: %v", call.Fun)
	}

	master := tfun.Master
	typ := master.Decl.Type

	var patterns []ast.Expr
	ellipsis := call.Ellipsis != token.NoPos
	variadic := false
	// collect template function param types expressions
	if fields := typ.Params; fields != nil {
		if n := len(fields.List); n != 0 {
			_, variadic = fields.List[n-1].Type.(*ast.Ellipsis)
			for _, field := range fields.List {
				for _ = range field.Names {
					patterns = append(patterns, field.Type)
				}
			}
		}
	}
	if variadic && !ellipsis {
		c.Errorf("unimplemented type inference on variadic template function: %v", call)
	} else if !variadic && ellipsis {
		c.Errorf("invalid use of ... in call to non-variadic template function: %v", call)
	}

	// collect call arg types
	nargs := len(args)
	var targs []xr.Type
	if nargs == 1 {
		arg := args[0]
		nargs = arg.NumOut()
		if nargs == 1 {
			targs = []xr.Type{arg.Type}
		} else {
			targs = arg.Types
		}
	} else {
		targs = make([]xr.Type, nargs)
		for i, arg := range args {
			targs[i] = arg.Type
		}
	}
	if nargs != len(patterns) {
		c.Errorf("template function %v has %d params, cannot call with %d values: %v", tfun, len(patterns), nargs, call)
	}
	inferred := make(map[string]inferredType)
	for _, name := range master.Params {
		inferred[name] = inferredType{}
	}
	inf := inferFuncType{comp: c, tfun: tfun, funcname: funcname, inferred: inferred, patterns: patterns, targs: targs, call: call}
	vals, types := inf.args()
	maker := &templateMaker{
		comp: upc, sym: fun.Sym, ifun: fun.Sym.Value,
		exprs: nil, vals: vals, types: types,
		ikey: makeTemplateKey(vals, types),
		pos:  inf.call.Pos(),
	}
	return c.templateFunc(maker, call)
}

// infer type of template function from arguments
func (inf *inferFuncType) args() (vals []I, types []xr.Type) {
	for i, targ := range inf.targs {
		inf.arg(inf.patterns[i], targ, false)
	}
	params := inf.tfun.Master.Params
	n := len(params)
	vals = make([]I, n)
	types = make([]xr.Type, n)
	for i, name := range params {
		inferred, ok := inf.inferred[name]
		if !ok || inferred.Type == nil {
			inf.comp.Errorf("failed to infer %v in call to template function: %v", name, inf.call)
		}
		types[i] = inferred.Type
		// TODO: also infer values
	}
	return vals, types
}

// partially infer type of template function for a single parameter
func (inf *inferFuncType) arg(pattern ast.Expr, targ xr.Type, exact bool) xr.Type {
	stars := 0
	tret := targ
	for {
		switch node := pattern.(type) {
		case *ast.Ident:
			inf.ident(node, targ, exact)
		case *ast.ArrayType:
			pattern, targ, exact = inf.arrayType(node, targ, exact)
			continue
		case *ast.ChanType:
			pattern, targ, exact = inf.chanType(node, targ, exact)
			continue
		case *ast.FuncType:
			pattern, targ, exact = inf.funcType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.IndexExpr:
			// function's parameter is itself a template
			pattern, targ, exact = inf.templateType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.InterfaceType:
			pattern, targ, exact = inf.interfaceType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.MapType:
			pattern, targ, exact = inf.mapType(node, targ, exact)
			continue
		case *ast.ParenExpr:
			pattern = node.X
			continue
		case *ast.SelectorExpr:
			// packagename.typename
			pattern, targ, exact = inf.selector(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.StarExpr:
			inf.is(pattern, targ, r.Ptr)
			pattern, targ = node.X, targ.Elem()
			if stars != 0 {
				exact = true
			}
			stars++
			continue
		case *ast.StructType:
			pattern, targ, exact = inf.structType(node, targ, exact)
			if pattern != nil {
				continue
			}
		default:
			inf.unimplemented(node, targ)
		}
		break
	}
	return tret
}

// partially infer type of template function from an array or slice parameter
func (inf *inferFuncType) arrayType(node *ast.ArrayType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	if node.Len == nil {
		inf.is(node, targ, r.Slice)
	} else {
		inf.is(node, targ, r.Array)
		if _, ok := node.Len.(*ast.Ellipsis); !ok {
			// [n]array
			inf.constant(node.Len, targ.Len())
		}
	}
	return node.Elt, targ.Elem(), true
}

// partially infer type of template function for a channel parameter
func (inf *inferFuncType) chanType(node *ast.ChanType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	inf.is(node, targ, r.Chan)
	tdir := targ.ChanDir()
	dir := reflectChanDir(node.Dir)
	if dir&tdir == 0 || (exact && dir != tdir) {
		inf.fail(node, targ)
	}
	return node.Value, targ.Elem(), true
}

// partially infer type of template function for a constant parameter
func (inf *inferFuncType) constant(node ast.Expr, val interface{}) {
	// TODO
	inf.comp.ErrorAt(node.Pos(), "unimplemented type inference: template function with parameter type %v and argument %v: %v",
		node, val, inf.call)
}

// partially infer type of template function for a func parameter
func (inf *inferFuncType) funcType(node *ast.FuncType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a func parameter
func (inf *inferFuncType) ident(node *ast.Ident, targ xr.Type, exact bool) {
	c := inf.comp
	name := node.Name
	inferred, ok := inf.inferred[name]
	if !ok {
		// name must be an existing type
		t := c.TryResolveType(name)
		if t == nil {
			c.ErrorAt(node.Pos(), "undefined identifier: %v", name)
		}
		if !targ.AssignableTo(t) {
			inf.comp.ErrorAt(node.Pos(),
				"type inference: mismatched types for %v: %v cannot be assigned to %v: %v",
				name, targ, t, inf.call)
		}
		return
	}

	// inferring one of the function template parameters
	if inferred.Type == nil {
		inf.inferred[name] = inferredType{Type: targ, Exact: exact}
		return
	}
	if !inferred.Type.IdenticalTo(targ) {
		if exact && inferred.Exact {
			inf.fail3(node, inferred.Type, targ)
		}
		fwd := targ.AssignableTo(inferred.Type)
		rev := inferred.Type.AssignableTo(targ)
		if inferred.Exact {
			if fwd {
				inf.fail3(node, inferred.Type, targ)
			}
		} else if exact {
			if rev {
				inferred.Type = targ
			} else {
				inf.fail3(node, inferred.Type, targ)
			}
		} else {
			if fwd && rev {
				if !targ.Named() {
					inferred.Type = targ
				}
			} else if fwd {
			} else if rev {
				inferred.Type = targ
			} else {
				inf.fail3(node, inferred.Type, targ)
			}
		}
	}
	if exact {
		inferred.Exact = true
	}
	inf.inferred[name] = inferred
}

// partially infer type of template function for an interface parameter
func (inf *inferFuncType) interfaceType(node *ast.InterfaceType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a map parameter
func (inf *inferFuncType) mapType(node *ast.MapType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	inf.is(node, targ, r.Map)
	inf.arg(node.Key, targ.Key(), true)
	return node.Value, targ.Elem(), true
}

// partially infer type of template function for an imported type
func (inf *inferFuncType) selector(node *ast.SelectorExpr, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a struct parameter
func (inf *inferFuncType) structType(node *ast.StructType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a template parameter
func (inf *inferFuncType) templateType(node *ast.IndexExpr, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

func (inf *inferFuncType) is(node ast.Expr, targ xr.Type, kind r.Kind) {
	if targ.Kind() != kind {
		inf.fail(node, targ)
	}
}

func (inf *inferFuncType) fail(node ast.Expr, targ xr.Type) {
	inf.comp.ErrorAt(node.Pos(),
		"type inference: in %v, parameter %v cannot match argument type <%v>: %v",
		inf, node, targ, inf.call)
}

func (inf *inferFuncType) fail3(node ast.Expr, tinferred xr.Type, targ xr.Type) {
	inf.comp.ErrorAt(node.Pos(),
		"type inference: in %v, parameter %v cannot match both <%v> and <%v>: %v",
		inf, node, tinferred, targ, inf.call)
}

func (inf *inferFuncType) unimplemented(node ast.Expr, targ xr.Type) (ast.Expr, xr.Type, bool) {
	inf.comp.ErrorAt(node.Pos(), "unimplemented type inference: in %v, parameter type %v with argument type %v: %v",
		inf, node, targ, inf.call)
	return nil, nil, false
}

var chandirs = map[ast.ChanDir]r.ChanDir{
	ast.RECV:            r.RecvDir,
	ast.SEND:            r.SendDir,
	ast.RECV | ast.SEND: r.BothDir,
}

func reflectChanDir(dir ast.ChanDir) r.ChanDir {
	return chandirs[dir]
}
<commit_msg>continue type inference on template functions<commit_after>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * template_infer.go
 *
 *  Created on Jun 06, 2018
 *      Author Massimiliano Ghilardi
 */

package fast

import (
	"fmt"
	"go/ast"
	"go/token"
	r "reflect"

	xr "github.com/cosmos72/gomacro/xreflect"
)

type inferType struct {
	Type    xr.Type
	Untyped r.Kind // for untyped literals
	Value   I      // in case we infer a constant, not a type
	Exact   bool
}

func untypedKindString(untyped r.Kind) string {
	var s string
	switch untyped {
	case r.Invalid:
		s = "nil"
	case r.Int32:
		s = "untyped rune"
	default:
		s = "untyped " + untyped.String()
	}
	return s
}

func (inf *inferType) String() string {
	if inf.Value != nil {
		return fmt.Sprint(inf.Value)
	}
	var s string
	if inf.Type != nil {
		s = inf.Type.String()
	} else {
		s = untypedKindString(inf.Untyped)
	}
	return "<" + s + ">"
}

// type inference on template functions
type inferFuncType struct {
	comp     *Comp
	tfun     *TemplateFunc
	funcname string
	inferred map[string]inferType
	patterns []ast.Expr
	targs    []inferType
	call     *ast.CallExpr // for error messages
}

func (inf *inferFuncType) String() string {
	return inf.tfun.Signature(inf.funcname)
}

func (c *Comp) inferTemplateFunc(call *ast.CallExpr, fun *Expr, args []*Expr) *Expr {
	tfun, ok := fun.Value.(*TemplateFunc)
	if !ok {
		c.Errorf("internal error: Comp.inferTemplateFunc() invoked on non-template function %v: %v", fun.Type, call.Fun)
	}
	var upc *Comp
	var funcname string
	{
		ident, ok := call.Fun.(*ast.Ident)
		if !ok {
			c.Errorf("unimplemented type inference on non-name template function %v: %v", call.Fun, call)
		}
		if fun.Sym == nil {
			c.Errorf("unimplemented type inference on non-symbol template function %v %#v: %v", call.Fun, fun, call)
		}
		// find the scope where fun is declared
		funcname = ident.Name
		fbind := &fun.Sym.Bind
		for upc = c; upc != nil; upc = upc.Outer {
			if bind, ok := upc.Binds[funcname]; ok && bind.Name == fbind.Name && bind.Desc == fbind.Desc && bind.Type.IdenticalTo(fbind.Type) {
				break
			}
		}
	}
	if upc == nil {
		c.Errorf("internal error: Comp.inferTemplateFunc() failed to determine the scope containing template function declaration: %v", call.Fun)
	}

	master := tfun.Master
	typ := master.Decl.Type

	var patterns []ast.Expr
	ellipsis := call.Ellipsis != token.NoPos
	variadic := false
	// collect template function param types expressions
	if fields := typ.Params; fields != nil {
		if n := len(fields.List); n != 0 {
			_, variadic = fields.List[n-1].Type.(*ast.Ellipsis)
			for _, field := range fields.List {
				for _ = range field.Names {
					patterns = append(patterns, field.Type)
				}
			}
		}
	}
	if variadic && !ellipsis {
		c.Errorf("unimplemented type inference on variadic template function: %v", call)
	} else if !variadic && ellipsis {
		c.Errorf("invalid use of ... in call to non-variadic template function: %v", call)
	}

	// collect call arg types
	nargs := len(args)
	var targs []inferType
	if nargs == 1 {
		arg := args[0]
		nargs = arg.NumOut()
		targs = make([]inferType, nargs)
		for i := 0; i < nargs; i++ {
			targs[i] = inferType{Type: arg.Out(i)}
		}
	} else {
		targs = make([]inferType, nargs)
		for i, arg := range args {
			if kind := arg.UntypedKind(); kind != r.Invalid {
				targs[i] = inferType{Untyped: kind}
			} else {
				targs[i] = inferType{Type: arg.Type}
			}
		}
	}
	if nargs != len(patterns) {
		c.Errorf("template function %v has %d params, cannot call with %d values: %v", tfun, len(patterns), nargs, call)
	}
	inferred := make(map[string]inferType)
	for _, name := range master.Params {
		inferred[name] = inferType{}
	}
	inf := inferFuncType{comp: c, tfun: tfun, funcname: funcname, inferred: inferred, patterns: patterns, targs: targs, call: call}
	vals, types := inf.args()
	maker := &templateMaker{
		comp: upc, sym: fun.Sym, ifun: fun.Sym.Value,
		exprs: nil, vals: vals, types: types,
		ikey: makeTemplateKey(vals, types),
		pos:  inf.call.Pos(),
	}
	return c.templateFunc(maker, call)
}

// infer type of template function from arguments
func (inf *inferFuncType) args() (vals []I, types []xr.Type) {
	exact := false // allow implicit type conversions

	// first pass: types and typed constants
	for i, targ := range inf.targs {
		node := inf.patterns[i]
		if targ.Type != nil {
			inf.arg(node, targ.Type, exact)
		} else if targ.Untyped != r.Invalid {
			// skip untyped constant, handled below
		} else if targ.Value != nil {
			inf.constant(node, targ.Value, exact)
		} else {
			inf.fail(node, targ)
		}
	}

	// second pass: untyped constants
	for i, targ := range inf.targs {
		if targ.Type == nil && targ.Untyped != r.Invalid {
			inf.untyped(inf.patterns[i], targ.Untyped, exact)
		}
	}

	params := inf.tfun.Master.Params
	n := len(params)
	vals = make([]I, n)
	types = make([]xr.Type, n)
	for i, name := range params {
		inferred, ok := inf.inferred[name]
		if !ok || inferred.Type == nil {
			inf.comp.Errorf("failed to infer %v in call to template function: %v", name, inf.call)
		}
		types[i] = inferred.Type
		vals[i] = inferred.Value
	}
	return vals, types
}

// partially infer type of template function for a single parameter
func (inf *inferFuncType) arg(pattern ast.Expr, targ xr.Type, exact bool) {
	stars := 0
	for {
		if targ == nil {
			inf.fail(pattern, targ)
		}
		if node, ok := pattern.(*ast.Ident); ok {
			inf.ident(node, targ, exact)
			break
		}
		switch node := pattern.(type) {
		case *ast.ArrayType:
			pattern, targ, exact = inf.arrayType(node, targ, exact)
			continue
		case *ast.ChanType:
			pattern, targ, exact = inf.chanType(node, targ, exact)
			continue
		case *ast.FuncType:
			pattern, targ, exact = inf.funcType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.IndexExpr:
			// function's parameter is itself a template
			pattern, targ, exact = inf.templateType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.InterfaceType:
			pattern, targ, exact = inf.interfaceType(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.MapType:
			pattern, targ, exact = inf.mapType(node, targ, exact)
			continue
		case *ast.ParenExpr:
			pattern = node.X
			continue
		case *ast.SelectorExpr:
			// packagename.typename
			pattern, targ, exact = inf.selector(node, targ, exact)
			if pattern != nil {
				continue
			}
		case *ast.StarExpr:
			inf.is(pattern, targ, r.Ptr)
			pattern, targ = node.X, targ.Elem()
			if stars != 0 {
				exact = true
			}
			stars++
			continue
		case *ast.StructType:
			pattern, targ, exact = inf.structType(node, targ, exact)
			if pattern != nil {
				continue
			}
		default:
			inf.unimplemented(node, targ)
		}
		break
	}
}

// partially infer type of template function from an array or slice parameter
func (inf *inferFuncType) arrayType(node *ast.ArrayType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	if node.Len == nil {
		inf.is(node, targ, r.Slice)
	} else {
		inf.is(node, targ, r.Array)
		if _, ok := node.Len.(*ast.Ellipsis); !ok {
			// [n]array
			inf.constant(node.Len, targ.Len(), exact)
		}
	}
	return node.Elt, targ.Elem(), true
}

// partially infer type of template function for a channel parameter
func (inf *inferFuncType) chanType(node *ast.ChanType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	inf.is(node, targ, r.Chan)
	tdir := targ.ChanDir()
	dir := reflectChanDir(node.Dir)
	if dir&tdir == 0 || (exact && dir != tdir) {
		inf.fail(node, targ)
	}
	return node.Value, targ.Elem(), true
}

// partially infer type of template function for a constant parameter
func (inf *inferFuncType) constant(node ast.Expr, val I, exact bool) {
	// TODO
	inf.comp.ErrorAt(node.Pos(), "unimplemented type inference: template function with parameter type %v and argument %v: %v",
		node, val, inf.call)
}

// partially infer type of template function for a func parameter
func (inf *inferFuncType) funcType(node *ast.FuncType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for an identifier parameter
func (inf *inferFuncType) ident(node *ast.Ident, targ xr.Type, exact bool) {
	c := inf.comp
	name := node.Name
	inferred, ok := inf.inferred[name]
	if !ok {
		// name must be an existing type
		t := c.TryResolveType(name)
		if t != nil {
			if !targ.AssignableTo(t) {
				inf.comp.ErrorAt(node.Pos(),
					"type inference: in %v, mismatched types for %v: %v cannot be assigned to %v: %v",
					inf, name, targ, t, inf.call)
			}
		}
		return
	}

	// inferring one of the function template parameters
	inf.combine(node, &inferred, inferType{Type: targ, Exact: exact})
	inf.inferred[name] = inferred

}

func (inf *inferFuncType) untyped(node ast.Expr, untyped r.Kind, exact bool) {
	ident, ok := node.(*ast.Ident)
	if !ok {
		inf.fail(node, untypedKindString(untyped))
	}
	inf.unimplemented(ident, untypedKindString(untyped))
}

func (inf *inferFuncType) combine(node ast.Expr, inferred *inferType, with inferType) {
	targ := with.Type
	exact := with.Exact
	if inferred.Type == nil {
		inferred.Type = targ
	} else if !inferred.Type.IdenticalTo(targ) {
		if exact && inferred.Exact {
			inf.fail3(node, inferred, targ)
		}
		fwd := targ.AssignableTo(inferred.Type)
		rev := inferred.Type.AssignableTo(targ)
		if inferred.Exact {
			if fwd {
				inf.fail3(node, inferred, targ)
			}
		} else if exact {
			if rev {
				inferred.Type = targ
			} else {
				inf.fail3(node, inferred, targ)
			}
		} else {
			if fwd && rev {
				if !targ.Named() {
					inferred.Type = targ
				}
			} else if fwd {
			} else if rev {
				inferred.Type = targ
			} else {
				inf.fail3(node, inferred, targ)
			}
		}
	}
	if exact {
		inferred.Exact = true
	}
}

// partially infer type of template function for an interface parameter
func (inf *inferFuncType) interfaceType(node *ast.InterfaceType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a map parameter
func (inf *inferFuncType) mapType(node *ast.MapType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	inf.is(node, targ, r.Map)
	inf.arg(node.Key, targ.Key(), true)
	return node.Value, targ.Elem(), true
}

// partially infer type of template function for an imported type
func (inf *inferFuncType) selector(node *ast.SelectorExpr, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a struct parameter
func (inf *inferFuncType) structType(node *ast.StructType, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

// partially infer type of template function for a template parameter
func (inf *inferFuncType) templateType(node *ast.IndexExpr, targ xr.Type, exact bool) (ast.Expr, xr.Type, bool) {
	// TODO
	return inf.unimplemented(node, targ)
}

func (inf *inferFuncType) is(node ast.Expr, targ xr.Type, kind r.Kind) {
	if targ.Kind() != kind {
		inf.fail(node, targ)
	}
}

func (inf *inferFuncType) fail(node ast.Expr, targ I) {
	inf.comp.ErrorAt(node.Pos(),
		"type inference: in %v, parameter %v cannot match argument type %v: %v",
		inf, node, targ, inf.call)
}

func (inf *inferFuncType) fail3(node ast.Expr, tinferred *inferType, targ xr.Type) {
	inf.comp.ErrorAt(node.Pos(),
		"type inference: in %v, parameter %v cannot match both %v and <%v>: %v",
		inf, node, tinferred, targ, inf.call)
}

func (inf *inferFuncType) unimplemented(node ast.Expr, targ I) (ast.Expr, xr.Type, bool) {
	inf.comp.ErrorAt(node.Pos(), "unimplemented type inference: in %v, parameter type %v with argument type %v: %v",
		inf, node, targ, inf.call)
	return nil, nil, false
}

var chandirs = map[ast.ChanDir]r.ChanDir{
	ast.RECV:            r.RecvDir,
	ast.SEND:            r.SendDir,
	ast.RECV | ast.SEND: r.BothDir,
}

func reflectChanDir(dir ast.ChanDir) r.ChanDir {
	return chandirs[dir]
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

// NodeType identifies the type of a parse tree node.
type NodeType int

const (
	// NodeSection is a section element.
	NodeSection NodeType = iota

	// NodeParagraph is a paragraph element.
	NodeParagraph

	// NodeAdornment is the overline or underline of a section.
	NodeAdornment

	// NodeBlockQuote is a blockquote element.
	NodeBlockQuote

	// NodeSystemMessage contains an error encountered by the parser.
	NodeSystemMessage

	// NodeLiteralBlock is a literal block element.
	NodeLiteralBlock

	// NodeIndent is indention encountered by the lexer. It can be any number
	// of spaces found before any other element type.
	NodeIndent

	// NodeTransition is a transition element. Transitions are very similar to
	// NodeSection except that they have newlines before and after.
	NodeTransition

	// NodeTitle is a section title element to be used inside SectionNodes.
	NodeTitle

	// NodeComment is a comment element
	NodeComment
)

var nodeTypes = [...]string{
	"NodeSection",
	"NodeParagraph",
	"NodeAdornment",
	"NodeBlockQuote",
	"NodeSystemMessage",
	"NodeLiteralBlock",
	"NodeIndent",
	"NodeTransition",
	"NodeTitle",
	"NodeComment",
}

// Type returns the type of a node element.
func (n NodeType) Type() NodeType {
	return n
}

func (n NodeType) String() string {
	return nodeTypes[n]
}

// Node is the interface used to implement parser nodes.
type Node interface {
	IDNumber() ID
	NodeType() NodeType
}

// NodeList is a list of parser nodes that implement Node.
type NodeList []Node

func (l *NodeList) append(n Node) {
	*l = append(*l, n)

}

// SectionNode is a a single section node. It contains overline, underline, and
// indentation nodes. NodeList contains nodes that are children of the section.
type SectionNode struct {
	ID   `json:"id"`
	Type NodeType `json:"type"`

	// Level is the hierarchical level of the section. The first level is level
	// 1, any further sections encountered after the first level are given
	// consecutive level numbers.
	Level int `json:"level"`

	// OverLine and UnderLine are the parsed Nodes that make up the section.
	Title     *TitleNode     `json:"title"`
	OverLine  *AdornmentNode `json:"overLine"`
	UnderLine *AdornmentNode `json:"underLine"`

	// Indent is indentation encountered by the parser before the SectionNode.
	// Sections cannot be indented, so this is primarily for error detection.
	Indent *IndentNode `json:"underLine"`

	// NodeList contains
	NodeList NodeList `json:"nodeList"`
}

// NodeType returns the Node type of the SectionNode.
func (s *SectionNode) NodeType() NodeType {
	return s.Type
}

func newSection(title *item, overSec *item, underSec *item, indent *item, id *int) *SectionNode {
	*id++
	n := &SectionNode{
		ID:   ID(*id),
		Type: NodeSection,
	}

	*id++
	n.Title = &TitleNode{
		ID:            ID(*id),
		Type:          NodeTitle,
		Text:          title.Text.(string),
		StartPosition: title.StartPosition,
		Length:        title.Length,
		Line:          title.Line,
	}

	if indent != nil && indent.Text != nil {
		*id++
		n.Indent = &IndentNode{
			ID:            ID(*id),
			Type:          NodeIndent,
			Text:          indent.Text.(string),
			StartPosition: indent.StartPosition,
			Line:          indent.Line,
			Length:        indent.Length,
		}
	}

	if overSec != nil && overSec.Text != nil {
		*id++
		Rune := rune(overSec.Text.(string)[0])
		n.OverLine = &AdornmentNode{
			ID:            ID(*id),
			Type:          NodeAdornment,
			Rune:          Rune,
			StartPosition: overSec.StartPosition,
			Line:          overSec.Line,
			Length:        overSec.Length,
		}
	}

	*id++
	Rune := rune(underSec.Text.(string)[0])
	n.UnderLine = &AdornmentNode{
		ID:            ID(*id),
		Rune:          Rune,
		Type:          NodeAdornment,
		StartPosition: underSec.StartPosition,
		Line:          underSec.Line,
		Length:        underSec.Length,
	}

	return n
}

// TitleNode contains the parsed data for a section titles.
type TitleNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

// NodeType returns the Node type of the TitleNode.
func (t TitleNode) NodeType() NodeType {
	return t.Type
}

// AdornmentNode contains the parsed data for a section overline or underline.
type AdornmentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Rune          rune     `json:"rune"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

// NodeType returns the Node type of the AdornmentNode.
func (a AdornmentNode) NodeType() NodeType {
	return a.Type
}

// ParagraphNode is a parsed paragraph.
type ParagraphNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

func newParagraph(i *item, id *int) *ParagraphNode {
	*id++
	return &ParagraphNode{
		ID:            ID(*id),
		Type:          NodeParagraph,
		Text:          i.Text.(string),
		Length:        i.Length,
		Line:          i.Line,
		StartPosition: i.StartPosition,
	}
}

// NodeType returns the Node type of the ParagraphNode.
func (p ParagraphNode) NodeType() NodeType {
	return p.Type
}

// BlockQuoteNode contains a parsed blockquote Node. Any nodes that are
// children of the blockquote are contained in NodeList.
type BlockQuoteNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Level         int      `json:"level"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
	// NodeList contains Nodes parsed as children of the BlockQuoteNode.
	NodeList NodeList `json:"nodeList"`
}

func newBlockQuote(i *item, indentLevel int, id *int) *BlockQuoteNode {
	*id++
	return &BlockQuoteNode{
		ID:            ID(*id),
		Type:          NodeBlockQuote,
		Level:         indentLevel,
		Line:          i.Line,
		StartPosition: i.StartPosition,
	}
}

// NodeType returns the Node type of the BlockQuoteNode.
func (b BlockQuoteNode) NodeType() NodeType {
	return b.Type
}

// SystemMessageNode are messages generated by the parser. System messages are
// leveled by severity and can be one of either Warning, Error, Info, and
// Severe.
type SystemMessageNode struct {
	ID   `json:"id"`
	Type NodeType `json:"type"`
	Line `json:"line"`

	// Severity is the level of importance of the message. It can be one of
	// either info, warning, error, and severe.
	Severity systemMessageLevel `json:"severity"`

	// NodeList contains children Nodes of the systemMessage. Typically
	// containing the first list item as a NodeParagraph which contains the
	// message, and a NodeLiteralBlock which contains the input data causing
	// the systemMessage to be generated.
	NodeList NodeList `json:"nodeList"`
}

func newSystemMessage(i *item, severity systemMessageLevel, id *int) *SystemMessageNode {
	*id++
	return &SystemMessageNode{
		ID:       ID(*id),
		Type:     NodeSystemMessage,
		Severity: severity,
		Line:     i.Line,
	}
}

// NodeType returns the Node type of the SystemMessageNode.
func (s SystemMessageNode) NodeType() NodeType {
	return s.Type
}

// LiteralBlockNode is a parsed literal block element.
type LiteralBlockNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newLiteralBlock(i *item, id *int) *LiteralBlockNode {
	*id++
	return &LiteralBlockNode{
		ID:            ID(*id),
		Type:          NodeLiteralBlock,
		Text:          i.Text.(string),
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of LiteralBlockNode.
func (l LiteralBlockNode) NodeType() NodeType {
	return l.Type
}

// IndentNode is any indentation encountered by the parser before block level
// elements.
type IndentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

// NodeType returns the Node type of IndentNode.
func (i IndentNode) NodeType() NodeType {
	return i.Type
}

// TransitionNode is a parsed transition element. Transition elements are very
// similar to AdornmentNodes.
type TransitionNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newTransition(i *item, id *int) *TransitionNode {
	*id++
	return &TransitionNode{
		ID:            ID(*id),
		Type:          NodeTransition,
		Text:          i.Text.(string),
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of the TransitionNode.
func (t TransitionNode) NodeType() NodeType {
	return t.Type
}

// CommentNode is a parsed comment element. Comment elements do not appear as
// visible elements in document transformations.
type CommentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newComment(i *item, id *int) *CommentNode {
	*id++
	return &CommentNode{
		ID:            ID(*id),
		Type:          NodeComment,
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of the CommentNode.
func (t CommentNode) NodeType() NodeType {
	return t.Type
}
<commit_msg>node.go: Add EnumListType<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

// NodeType identifies the type of a parse tree node.
type NodeType int

const (
	// NodeSection is a section element.
	NodeSection NodeType = iota

	// NodeParagraph is a paragraph element.
	NodeParagraph

	// NodeAdornment is the overline or underline of a section.
	NodeAdornment

	// NodeBlockQuote is a blockquote element.
	NodeBlockQuote

	// NodeSystemMessage contains an error encountered by the parser.
	NodeSystemMessage

	// NodeLiteralBlock is a literal block element.
	NodeLiteralBlock

	// NodeIndent is indention encountered by the lexer. It can be any number
	// of spaces found before any other element type.
	NodeIndent

	// NodeTransition is a transition element. Transitions are very similar to
	// NodeSection except that they have newlines before and after.
	NodeTransition

	// NodeTitle is a section title element to be used inside SectionNodes.
	NodeTitle

	// NodeComment is a comment element
	NodeComment
)

var nodeTypes = [...]string{
	"NodeSection",
	"NodeParagraph",
	"NodeAdornment",
	"NodeBlockQuote",
	"NodeSystemMessage",
	"NodeLiteralBlock",
	"NodeIndent",
	"NodeTransition",
	"NodeTitle",
	"NodeComment",
}

// Type returns the type of a node element.
func (n NodeType) Type() NodeType {
	return n
}

func (n NodeType) String() string {
	return nodeTypes[n]
}

// Node is the interface used to implement parser nodes.
type Node interface {
	IDNumber() ID
	NodeType() NodeType
}

// NodeList is a list of parser nodes that implement Node.
type NodeList []Node

func (l *NodeList) append(n Node) {
	*l = append(*l, n)
}

type EnumListType int

const (
	enumListArabic EnumListType = iota
	enumListUpperAlpha
	enumListLowerAlpha
	enumListUpperRoman
	enumListLowerRoman
	enumListAuto
)

var enumListTypes = [...]string{
	"enumListArabic",
	"enumListUpperAlpha",
	"enumListLowerAlpha",
	"enumListUpperRoman",
	"enumListLowerRoman",
	"enumListAuto",
}

func (e EnumListType) String() string {
	return enumListTypes[e]
}

// SectionNode is a a single section node. It contains overline, underline, and
// indentation nodes. NodeList contains nodes that are children of the section.
type SectionNode struct {
	ID   `json:"id"`
	Type NodeType `json:"type"`

	// Level is the hierarchical level of the section. The first level is level
	// 1, any further sections encountered after the first level are given
	// consecutive level numbers.
	Level int `json:"level"`

	// OverLine and UnderLine are the parsed Nodes that make up the section.
	Title     *TitleNode     `json:"title"`
	OverLine  *AdornmentNode `json:"overLine"`
	UnderLine *AdornmentNode `json:"underLine"`

	// Indent is indentation encountered by the parser before the SectionNode.
	// Sections cannot be indented, so this is primarily for error detection.
	Indent *IndentNode `json:"underLine"`

	// NodeList contains
	NodeList NodeList `json:"nodeList"`
}

// NodeType returns the Node type of the SectionNode.
func (s *SectionNode) NodeType() NodeType {
	return s.Type
}

func newSection(title *item, overSec *item, underSec *item, indent *item, id *int) *SectionNode {
	*id++
	n := &SectionNode{
		ID:   ID(*id),
		Type: NodeSection,
	}

	*id++
	n.Title = &TitleNode{
		ID:            ID(*id),
		Type:          NodeTitle,
		Text:          title.Text.(string),
		StartPosition: title.StartPosition,
		Length:        title.Length,
		Line:          title.Line,
	}

	if indent != nil && indent.Text != nil {
		*id++
		n.Indent = &IndentNode{
			ID:            ID(*id),
			Type:          NodeIndent,
			Text:          indent.Text.(string),
			StartPosition: indent.StartPosition,
			Line:          indent.Line,
			Length:        indent.Length,
		}
	}

	if overSec != nil && overSec.Text != nil {
		*id++
		Rune := rune(overSec.Text.(string)[0])
		n.OverLine = &AdornmentNode{
			ID:            ID(*id),
			Type:          NodeAdornment,
			Rune:          Rune,
			StartPosition: overSec.StartPosition,
			Line:          overSec.Line,
			Length:        overSec.Length,
		}
	}

	*id++
	Rune := rune(underSec.Text.(string)[0])
	n.UnderLine = &AdornmentNode{
		ID:            ID(*id),
		Rune:          Rune,
		Type:          NodeAdornment,
		StartPosition: underSec.StartPosition,
		Line:          underSec.Line,
		Length:        underSec.Length,
	}

	return n
}

// TitleNode contains the parsed data for a section titles.
type TitleNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

// NodeType returns the Node type of the TitleNode.
func (t TitleNode) NodeType() NodeType {
	return t.Type
}

// AdornmentNode contains the parsed data for a section overline or underline.
type AdornmentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Rune          rune     `json:"rune"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

// NodeType returns the Node type of the AdornmentNode.
func (a AdornmentNode) NodeType() NodeType {
	return a.Type
}

// ParagraphNode is a parsed paragraph.
type ParagraphNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
}

func newParagraph(i *item, id *int) *ParagraphNode {
	*id++
	return &ParagraphNode{
		ID:            ID(*id),
		Type:          NodeParagraph,
		Text:          i.Text.(string),
		Length:        i.Length,
		Line:          i.Line,
		StartPosition: i.StartPosition,
	}
}

// NodeType returns the Node type of the ParagraphNode.
func (p ParagraphNode) NodeType() NodeType {
	return p.Type
}

// BlockQuoteNode contains a parsed blockquote Node. Any nodes that are
// children of the blockquote are contained in NodeList.
type BlockQuoteNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Level         int      `json:"level"`
	Line          `json:"line"`
	StartPosition `json:"startPosition"`
	// NodeList contains Nodes parsed as children of the BlockQuoteNode.
	NodeList NodeList `json:"nodeList"`
}

func newBlockQuote(i *item, indentLevel int, id *int) *BlockQuoteNode {
	*id++
	return &BlockQuoteNode{
		ID:            ID(*id),
		Type:          NodeBlockQuote,
		Level:         indentLevel,
		Line:          i.Line,
		StartPosition: i.StartPosition,
	}
}

// NodeType returns the Node type of the BlockQuoteNode.
func (b BlockQuoteNode) NodeType() NodeType {
	return b.Type
}

// SystemMessageNode are messages generated by the parser. System messages are
// leveled by severity and can be one of either Warning, Error, Info, and
// Severe.
type SystemMessageNode struct {
	ID   `json:"id"`
	Type NodeType `json:"type"`
	Line `json:"line"`

	// Severity is the level of importance of the message. It can be one of
	// either info, warning, error, and severe.
	Severity systemMessageLevel `json:"severity"`

	// NodeList contains children Nodes of the systemMessage. Typically
	// containing the first list item as a NodeParagraph which contains the
	// message, and a NodeLiteralBlock which contains the input data causing
	// the systemMessage to be generated.
	NodeList NodeList `json:"nodeList"`
}

func newSystemMessage(i *item, severity systemMessageLevel, id *int) *SystemMessageNode {
	*id++
	return &SystemMessageNode{
		ID:       ID(*id),
		Type:     NodeSystemMessage,
		Severity: severity,
		Line:     i.Line,
	}
}

// NodeType returns the Node type of the SystemMessageNode.
func (s SystemMessageNode) NodeType() NodeType {
	return s.Type
}

// LiteralBlockNode is a parsed literal block element.
type LiteralBlockNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newLiteralBlock(i *item, id *int) *LiteralBlockNode {
	*id++
	return &LiteralBlockNode{
		ID:            ID(*id),
		Type:          NodeLiteralBlock,
		Text:          i.Text.(string),
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of LiteralBlockNode.
func (l LiteralBlockNode) NodeType() NodeType {
	return l.Type
}

// IndentNode is any indentation encountered by the parser before block level
// elements.
type IndentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

// NodeType returns the Node type of IndentNode.
func (i IndentNode) NodeType() NodeType {
	return i.Type
}

// TransitionNode is a parsed transition element. Transition elements are very
// similar to AdornmentNodes.
type TransitionNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newTransition(i *item, id *int) *TransitionNode {
	*id++
	return &TransitionNode{
		ID:            ID(*id),
		Type:          NodeTransition,
		Text:          i.Text.(string),
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of the TransitionNode.
func (t TransitionNode) NodeType() NodeType {
	return t.Type
}

// CommentNode is a parsed comment element. Comment elements do not appear as
// visible elements in document transformations.
type CommentNode struct {
	ID            `json:"id"`
	Type          NodeType `json:"type"`
	Text          string   `json:"text"`
	Length        int      `json:"length"`
	StartPosition `json:"startPosition"`
	Line          `json:"line"`
}

func newComment(i *item, id *int) *CommentNode {
	*id++
	return &CommentNode{
		ID:            ID(*id),
		Type:          NodeComment,
		Length:        i.Length,
		StartPosition: i.StartPosition,
		Line:          i.Line,
	}
}

// NodeType returns the Node type of the CommentNode.
func (t CommentNode) NodeType() NodeType {
	return t.Type
}
<|endoftext|>


<commit_before>package jodaTime

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestParse(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss.SSSSSSSSS", "03/02/2007 23:10:05.000000004",
			time.Date(2007, time.February, 3, 23, 10, 5, 4, time.UTC)},

		{"dd/MMMM/yyyy:HH:mm:ss Z", "30/August/2015:21:44:25 -0500",
			time.Date(2015, time.August, 30, 21, 44, 25, 0, time.FixedZone("", -5*60*60))},

		{"dd/MMMM/yyyy:hh:m:s a Z", "30/August/2015:03:4:5 PM -0500",
			time.Date(2015, time.August, 30, 15, 4, 5, 0, time.FixedZone("", -5*60*60))},

		{"dd/MMMM/yyyy:hh:m:s a Z", "30/August/2015:03:4:25 PM -0500",
			time.Date(2015, time.August, 30, 15, 4, 25, 0, time.FixedZone("", -5*60*60))},

		{"YYYY-MM-dd HH:mm:ss.SSS", "2012-12-22 12:53:30.000",
			time.Date(2012, time.December, 22, 12, 53, 30, 0, time.UTC)},
		{"E d-MMMM-YY HH:mm:ss.SSS", "Mon 1-may-17 12:53:30.000",
			time.Date(2017, time.May, 1, 12, 53, 30, 0, time.UTC)},
		{"[EEE MMM dd HH:mm:ss y]", "[Sun Jan 11 10:43:35 2015]",
			time.Date(2015, time.January, 11, 10, 43, 35, 0, time.UTC)},
		{"[EEEE MMM dd HH:mm:ss y]", "[Sunday Jan 11 10:43:35 2015]",
			time.Date(2015, time.January, 11, 10, 43, 35, 0, time.UTC)},
		{"[EEEE M dd h:mm:ss y]", "[Sunday 1 11 9:43:35 2015]",
			time.Date(2015, time.January, 11, 9, 43, 35, 0, time.UTC)},

		{"dd/MMMM/yyyy:hh:m:s a ZZ", "30/August/2015:03:4:25 PM -05:00",
			time.Date(2015, time.August, 30, 15, 4, 25, 0, time.FixedZone("", -5*60*60))},
	}

	for _, test := range tests {
		rTime, err := Parse(test.format, test.value)
		// z, o := rTime.Zone()
		// pp.Println("rTime, zone, offset-->", rTime, z, o/3600)

		assert.NoError(t, err)
		assert.Equal(t, test.expected, rTime, "("+test.format+") they should be equal")
	}
}

func TestParseInLocation(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		location string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss", "03/02/2007 23:10:05", "Europe/Paris",
			time.Date(2007, time.February, 3, 23, 10, 5, 0, time.FixedZone("CET", 3600))},
	}

	for _, test := range tests {
		rTime, err := ParseInLocation(test.format, test.value, test.location)
		assert.NoError(t, err)
		assert.Equal(t, test.expected.Format("RFC1123Z"), rTime.Format("RFC1123Z"), "("+test.format+") they should be equal")
	}
}

func TestParseInLocationError(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		location string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss", "03/02/2007 23:10:05", "Space/Moon",
			time.Date(2007, time.February, 3, 23, 10, 5, 0, time.FixedZone("CET", 3600))},
	}

	for _, test := range tests {
		_, err := ParseInLocation(test.format, test.value, test.location)
		assert.Error(t, err)
	}
}
<commit_msg>add tests<commit_after>package jodaTime

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestParse(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss.SSSSSSSSS P", "03/02/2007 23:10:05.000000004 P",
			time.Date(2007, time.February, 3, 23, 10, 5, 4, time.UTC)},

		{"dd/MMMM/yyyy:HH:mm:ss Z", "30/August/2015:21:44:25 -0500",
			time.Date(2015, time.August, 30, 21, 44, 25, 0, time.FixedZone("", -5*60*60))},

		{"dd/MMMM/yyyy:hh:m:s a Z P", "30/August/2015:03:4:5 PM -0500 P",
			time.Date(2015, time.August, 30, 15, 4, 5, 0, time.FixedZone("", -5*60*60))},

		{"dd/MMMM/yyyy:hh:m:s a Z", "30/August/2015:03:4:25 PM -0500",
			time.Date(2015, time.August, 30, 15, 4, 25, 0, time.FixedZone("", -5*60*60))},

		{"YYYY-MM-dd HH:mm:ss.SSS", "2012-12-22 12:53:30.000",
			time.Date(2012, time.December, 22, 12, 53, 30, 0, time.UTC)},
		{"E d-MMMM-YY HH:mm:ss.SSS", "Mon 1-may-17 12:53:30.000",
			time.Date(2017, time.May, 1, 12, 53, 30, 0, time.UTC)},
		{"[EEE MMM dd HH:mm:ss y]", "[Sun Jan 11 10:43:35 2015]",
			time.Date(2015, time.January, 11, 10, 43, 35, 0, time.UTC)},
		{"[EEEE MMM dd HH:mm:ss y]", "[Sunday Jan 11 10:43:35 2015]",
			time.Date(2015, time.January, 11, 10, 43, 35, 0, time.UTC)},
		{"[EEEE M dd h:mm:ss y]", "[Sunday 1 11 9:43:35 2015]",
			time.Date(2015, time.January, 11, 9, 43, 35, 0, time.UTC)},

		{"dd/MMMM/yyyy:hh:m:s a ZZ", "30/August/2015:03:4:25 PM -05:00",
			time.Date(2015, time.August, 30, 15, 4, 25, 0, time.FixedZone("", -5*60*60))},
	}

	for _, test := range tests {
		rTime, err := Parse(test.format, test.value)
		// z, o := rTime.Zone()
		// pp.Println("rTime, zone, offset-->", rTime, z, o/3600)

		assert.NoError(t, err)
		assert.Equal(t, test.expected, rTime, "("+test.format+") they should be equal")
	}
}

func TestParseInLocation(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		location string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss", "03/02/2007 23:10:05", "Europe/Paris",
			time.Date(2007, time.February, 3, 23, 10, 5, 0, time.FixedZone("CET", 3600))},
	}

	for _, test := range tests {
		rTime, err := ParseInLocation(test.format, test.value, test.location)
		assert.NoError(t, err)
		assert.Equal(t, test.expected.Format("RFC1123Z"), rTime.Format("RFC1123Z"), "("+test.format+") they should be equal")
	}
}

func TestParseInLocationError(t *testing.T) {
	tests := []struct {
		format   string
		value    string
		location string
		expected time.Time
	}{
		{"dd/MM/YYYY HH:mm:ss", "03/02/2007 23:10:05", "Space/Moon",
			time.Date(2007, time.February, 3, 23, 10, 5, 0, time.FixedZone("CET", 3600))},
	}

	for _, test := range tests {
		_, err := ParseInLocation(test.format, test.value, test.location)
		assert.Error(t, err)
	}
}
<|endoftext|>


<commit_before>package main
import (
    "path/filepath"
    "howett.net/plist"
    "os"
    "flag"
    "fmt"
)

type weblocHeader struct {
    URL string `plist:"URL"`
}

var delete bool
var noop bool

func init() {
    flag.BoolVar(&delete, "delete", false, "delete .webloc files after conversion")
    flag.BoolVar(&noop, "noop", false, "decode urls, but do not change file system")
    flag.Parse()
}

func main() {
    root := flag.Arg(0)
    filepath.Walk(root, walkpath)
}

func walkpath(path string, f os.FileInfo, err error) error {
    if err != nil {
        return err
    }
    matched, err := filepath.Match("*.webloc", f.Name())
    if err != nil {
        return err
    }
    if matched {
        process(path)
    }
    return nil
}

func process(path string) {
    url := decode(path)
    fmt.Println(url)

    if ! noop {
        writeUrl(path[:len(path)-len(".webloc")] + ".url", url)
        if delete {
            err := os.Remove(path)
            check(err)
        }
    }
}

func decode(path string) string {
    var data weblocHeader

    f, err := os.Open(path)
    check(err)
    defer f.Close()

    decoder := plist.NewDecoder(f)
    check(decoder.Decode(&data))
    return data.URL
}

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func writeUrl(path string, url string) {
    f, err := os.Create(path)
    check(err)
    defer f.Close()

    f.WriteString("[InternetShortcut]\nURL=" + url)
}
<commit_msg>go fmt<commit_after>package main

import (
	"flag"
	"fmt"
	"howett.net/plist"
	"os"
	"path/filepath"
)

type weblocHeader struct {
	URL string `plist:"URL"`
}

var delete bool
var noop bool

func init() {
	flag.BoolVar(&delete, "delete", false, "delete .webloc files after conversion")
	flag.BoolVar(&noop, "noop", false, "decode urls, but do not change file system")
	flag.Parse()
}

func main() {
	root := flag.Arg(0)
	filepath.Walk(root, walkpath)
}

func walkpath(path string, f os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	matched, err := filepath.Match("*.webloc", f.Name())
	if err != nil {
		return err
	}
	if matched {
		process(path)
	}
	return nil
}

func process(path string) {
	url := decode(path)
	fmt.Println(url)

	if !noop {
		writeUrl(path[:len(path)-len(".webloc")]+".url", url)
		if delete {
			err := os.Remove(path)
			check(err)
		}
	}
}

func decode(path string) string {
	var data weblocHeader

	f, err := os.Open(path)
	check(err)
	defer f.Close()

	decoder := plist.NewDecoder(f)
	check(decoder.Decode(&data))
	return data.URL
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func writeUrl(path string, url string) {
	f, err := os.Create(path)
	check(err)
	defer f.Close()

	f.WriteString("[InternetShortcut]\nURL=" + url)
}
<|endoftext|>