<commit_before>//
// +build unit

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

Copyright 2015 Intel Corporation

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 movingaverage

import (
	"bytes"
	"encoding/gob"
	"math/rand"
	"testing"
	"time"

	"github.com/intelsdi-x/pulse/control/plugin"
	"github.com/intelsdi-x/pulse/control/plugin/cpolicy"
	"github.com/intelsdi-x/pulse/core/ctypes"
	. "github.com/smartystreets/goconvey/convey"
)

//Random number generator
func randInt(min int, max int) int {
	return min + rand.Intn(max-min)
}

func TestMovingAverageProcessor(t *testing.T) {
	meta := Meta()
	Convey("Meta should return metadata for the plugin", t, func() {
		Convey("So meta.Name should equal movingaverage", func() {
			So(meta.Name, ShouldEqual, "movingaverage")
		})
		Convey("So meta.Version should equal 3", func() {
			So(meta.Version, ShouldEqual, 3)
		})
		Convey("So meta.Type should be of type plugin.ProcessorPluginType", func() {
			So(meta.Type, ShouldResemble, plugin.ProcessorPluginType)
		})
	})

	proc := NewMovingaverageProcessor()
	Convey("Create Movingaverage processor", t, func() {
		Convey("So proc should not be nil", func() {
			So(proc, ShouldNotBeNil)
		})
		Convey("So proc should be of type movingAverageProcessor", func() {
			So(proc, ShouldHaveSameTypeAs, &movingAverageProcessor{})
		})
		Convey("proc.GetConfigPolicy should return a config policy", func() {
			configPolicy, _ := proc.GetConfigPolicy()
			Convey("So config policy should be a cpolicy.ConfigPolicy", func() {
				So(configPolicy, ShouldHaveSameTypeAs, &cpolicy.ConfigPolicy{})
			})
			testConfig := make(map[string]ctypes.ConfigValue)
			testConfig["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: 10}
			cfg, errs := configPolicy.Get([]string{""}).Process(testConfig)
			Convey("So config policy should process testConfig and return a config", func() {
				So(cfg, ShouldNotBeNil)
			})
			Convey("So testConfig processing should return no errors", func() {
				So(errs.HasErrors(), ShouldBeFalse)
			})
		})
	})
}

func TestMovingAverageProcessorMetrics(t *testing.T) {
	Convey("Moving Average Processor tests", t, func() {
		metrics := make([]plugin.PluginMetricType, 10)
		config := make(map[string]ctypes.ConfigValue)

		config["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: -1}

		Convey("Moving average for int data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", data)
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), config)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for float32 data", func() {
			config["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: 40}
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", float32(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), config)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})
		Convey("Moving average for float64 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", float64(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for uint32 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", uint32(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for uint64 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", uint64(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for unknown data type", func() {
			for i, _ := range metrics {

				data := "I am an unknow data Type"
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", data)
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

	})
}
<commit_msg>fix integration test<commit_after>//
// +build unit

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

Copyright 2015 Intel Corporation

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 movingaverage

import (
	"bytes"
	"encoding/gob"
	"math/rand"
	"testing"
	"time"

	"github.com/intelsdi-x/pulse/control/plugin"
	"github.com/intelsdi-x/pulse/control/plugin/cpolicy"
	"github.com/intelsdi-x/pulse/core/ctypes"
	. "github.com/smartystreets/goconvey/convey"
)

//Random number generator
func randInt(min int, max int) int {
	return min + rand.Intn(max-min)
}

func TestMovingAverageProcessor(t *testing.T) {
	meta := Meta()
	Convey("Meta should return metadata for the plugin", t, func() {
		Convey("So meta.Name should equal movingaverage", func() {
			So(meta.Name, ShouldEqual, "movingaverage")
		})
		Convey("So meta.Version should equal 3", func() {
			So(meta.Version, ShouldEqual, 3)
		})
		Convey("So meta.Type should be of type plugin.ProcessorPluginType", func() {
			So(meta.Type, ShouldResemble, plugin.ProcessorPluginType)
		})
	})

	proc := NewMovingaverageProcessor()
	Convey("Create Movingaverage processor", t, func() {
		Convey("So proc should not be nil", func() {
			So(proc, ShouldNotBeNil)
		})
		Convey("So proc should be of type movingAverageProcessor", func() {
			So(proc, ShouldHaveSameTypeAs, &movingAverageProcessor{})
		})
		Convey("proc.GetConfigPolicy should return a config policy", func() {
			configPolicy, _ := proc.GetConfigPolicy()
			Convey("So config policy should be a cpolicy.ConfigPolicy", func() {
				So(configPolicy, ShouldHaveSameTypeAs, &cpolicy.ConfigPolicy{})
			})
			testConfig := make(map[string]ctypes.ConfigValue)
			testConfig["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: 10}
			cfg, errs := configPolicy.Get([]string{""}).Process(testConfig)
			Convey("So config policy should process testConfig and return a config", func() {
				So(cfg, ShouldNotBeNil)
			})
			Convey("So testConfig processing should return no errors", func() {
				So(errs.HasErrors(), ShouldBeFalse)
			})
		})
	})
}

func TestMovingAverageProcessorMetrics(t *testing.T) {
	Convey("Moving Average Processor tests", t, func() {
		metrics := make([]plugin.PluginMetricType, 10)
		config := make(map[string]ctypes.ConfigValue)

		config["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: -1}

		Convey("Moving average for int data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, data)
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), config)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for float32 data", func() {
			config["MovingAvgBufLength"] = ctypes.ConfigValueInt{Value: 40}
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, float32(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), config)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})
		Convey("Moving average for float64 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, float64(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for uint32 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, uint32(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for uint64 data", func() {
			for i, _ := range metrics {
				time.Sleep(3)
				rand.Seed(time.Now().UTC().UnixNano())
				data := randInt(65, 90)
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, uint64(data))
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)
			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

		Convey("Moving average for unknown data type", func() {
			for i, _ := range metrics {

				data := "I am an unknow data Type"
				metrics[i] = *plugin.NewPluginMetricType([]string{"foo", "bar"}, time.Now(), "", nil, nil, data)
			}
			var buf bytes.Buffer
			enc := gob.NewEncoder(&buf)
			enc.Encode(metrics)

			movingAverageObj := NewMovingaverageProcessor()

			_, received_data, _ := movingAverageObj.Process("pulse.gob", buf.Bytes(), nil)

			var metrics_new []plugin.PluginMetricType

			//Decodes the content into pluginMetricType
			dec := gob.NewDecoder(bytes.NewBuffer(received_data))
			dec.Decode(&metrics_new)
			So(metrics, ShouldNotResemble, metrics_new)

		})

	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"os"
	"strings"
	"time"

	grpcServer "github.com/linkerd/linkerd-examples/docker/helloworld/grpc"
	httpServer "github.com/linkerd/linkerd-examples/docker/helloworld/http"
	proto "github.com/linkerd/linkerd-examples/docker/helloworld/proto"
	"google.golang.org/grpc"
)

func dieIf(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
}

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

	addr := flag.String("addr", ":7777", "address to serve on")
	text := flag.String("text", "Hello", "text to serve")
	target := flag.String("target", "", "target service to call before returning")
	latency := flag.Duration("latency", 0, "time to sleep before processing request")
	failureRate := flag.Float64("failure-rate", 0.0, "rate of error responses to return")
	json := flag.Bool("json", false, "return JSON instead of plaintext responses (HTTP only)")
	protocol := flag.String("protocol", "http", "API protocol: http or grpc")
	flag.Parse()

	serverText := *text
	if envText := os.Getenv("TARGET_WORLD"); envText != "" {
		serverText = envText
	}

	podIp := os.Getenv("POD_IP")

	switch *protocol {
	case "http":
		server := &http.Server{
			Addr:         *addr,
			ReadTimeout:  5 * time.Second,
			WriteTimeout: 10 * time.Second,
			Handler:      httpServer.New(serverText, *target, podIp, *latency, *failureRate, *json),
		}

		fmt.Println("starting HTTP server on", *addr)

		err := server.ListenAndServe()
		dieIf(err)

	case "grpc":
		lis, err := net.Listen("tcp", *addr)
		dieIf(err)

		s := grpc.NewServer()
		server, err := grpcServer.New(serverText, *target, podIp, *latency, *failureRate)
		dieIf(err)

		if strings.ToLower(serverText) == "hello" {
			proto.RegisterHelloServer(s, server)
		} else {
			proto.RegisterWorldServer(s, server)
		}

		fmt.Println("starting gRPC server on", *addr)

		err = s.Serve(lis)
		dieIf(err)
	default:
		dieIf(fmt.Errorf("unsupported protocol: %s", *protocol))
	}
}
<commit_msg>Add graceful shutdown to helloworld apps (#185)<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"time"

	grpcServer "github.com/linkerd/linkerd-examples/docker/helloworld/grpc"
	httpServer "github.com/linkerd/linkerd-examples/docker/helloworld/http"
	proto "github.com/linkerd/linkerd-examples/docker/helloworld/proto"
	"google.golang.org/grpc"
)

const (
	httpTimeout = 10 * time.Second
)

func dieIf(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt)

	addr := flag.String("addr", ":7777", "address to serve on")
	text := flag.String("text", "Hello", "text to serve")
	target := flag.String("target", "", "target service to call before returning")
	latency := flag.Duration("latency", 0, "time to sleep before processing request")
	failureRate := flag.Float64("failure-rate", 0.0, "rate of error responses to return")
	json := flag.Bool("json", false, "return JSON instead of plaintext responses (HTTP only)")
	protocol := flag.String("protocol", "http", "API protocol: http or grpc")
	flag.Parse()

	serverText := *text
	if envText := os.Getenv("TARGET_WORLD"); envText != "" {
		serverText = envText
	}

	podIp := os.Getenv("POD_IP")

	switch *protocol {
	case "http":
		if *latency > httpTimeout {
			dieIf(fmt.Errorf("latency cannot exceed %s", httpTimeout))
		}

		server := &http.Server{
			Addr:         *addr,
			ReadTimeout:  httpTimeout + time.Second,
			WriteTimeout: httpTimeout + time.Second,
			Handler:      httpServer.New(serverText, *target, podIp, *latency, *failureRate, *json),
		}

		go func() {
			fmt.Println("starting HTTP server on", *addr)
			server.ListenAndServe()
		}()

		<-stop

		fmt.Println("shutting down HTTP server on", *addr)
		server.Shutdown(context.Background())

	case "grpc":
		lis, err := net.Listen("tcp", *addr)
		dieIf(err)

		s := grpc.NewServer()
		server, err := grpcServer.New(serverText, *target, podIp, *latency, *failureRate)
		dieIf(err)

		if strings.ToLower(serverText) == "hello" {
			proto.RegisterHelloServer(s, server)
		} else {
			proto.RegisterWorldServer(s, server)
		}

		go func() {
			fmt.Println("starting gRPC server on", *addr)
			s.Serve(lis)
		}()

		<-stop

		fmt.Println("shutting down gRPC server on", *addr)
		s.GracefulStop()

	default:
		dieIf(fmt.Errorf("unsupported protocol: %s", *protocol))
	}
}
<|endoftext|>


<commit_before><commit_msg>Fix mouse support in command bar<commit_after><|endoftext|>


<commit_before>package task

import (
	"sort"

	"nirenjan.org/overlord/internal/cmds/cli"
)

type TaskList []Task

func (tl TaskList) Len() int {
	return len(tl)
}

func (tl TaskList) Swap(i, j int) {
	tl[i], tl[j] = tl[j], tl[i]
}

func (tl TaskList) Less(i, j int) bool {
	t1 := tl[i]
	t2 := tl[j]

	// If deferred, completed or deleted, these should be towards the end
	if t1.State >= Deferred || t2.State >= Deferred {
		if t1.State != t2.State {
			return t1.State < t2.State
		}
	}

	// Compare the dates using the Equal function
	if !t1.Due.Equal(t2.Due) {
		return t1.Due.Sub(t2.Due) < 0
	}

	// If priorities are unequal, use them
	if t1.Priority != t2.Priority {
		return t1.Priority < t2.Priority
	}

	// All else being equal, sort by creation date
	return t1.Created.Sub(t2.Created) < 0
}

func registerListHandler(root *cli.Command) error {
	// task list
	cmd := cli.Cmd{
		Command:   "list",
		Usage:     "[type]",
		BriefHelp: "list all pending tasks",
		LongHelp: `
List all pending tasks. This includes tasks that are overdue, due shortly,
in progress (but not due shortly), and tasks that haven't been started.
`,
		Handler:    listHandler,
		Args:       cli.AtMost,
		Count:      1,
		Subcommand: "Task Types",
	}

	taskList, err := cli.RegisterCommandGroup(root, cmd)
	if err != nil {
		return err
	}

	// task list pending
	// This is the same as task list, so just change the relevant fields
	cmd.Command = "pending"
	cmd.Usage = " "
	cmd.Args = cli.None

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list overdue
	cmd = cli.Cmd{
		Command:   "overdue",
		Usage:     " ",
		BriefHelp: "list all overdue tasks",
		LongHelp: `
List all tasks that are past their due date, ordered by priority.
`,
		Handler: listHandler,
		Args:    cli.None,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list due
	cmd = cli.Cmd{
		Command:   "due",
		Usage:     " ",
		BriefHelp: "list all tasks due shortly",
		LongHelp: `
List all tasks that are due within the next week, ordered by the due
date, then by their priority.
`,
		Handler: listHandler,
		Args:    cli.None,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list in-progress
	cmd = cli.Cmd{
		Command:   "in-progress",
		Usage:     " ",
		BriefHelp: "list all tasks that are in progress",
		LongHelp: `
List all tasks that are currently in progress, ordered by the due date
and then by the priority.
`,
		Handler: listHandler,
		Args:    cli.None,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	return nil
}

func sortedTaskList() TaskList {
	tasks := make(TaskList, len(DB))
	i := 0
	for _, task := range DB {
		tasks[i] = task
		i++
	}

	sort.Sort(tasks)
	return tasks
}

func listHandler(cmd *cli.Command, args []string) error {
	err := LoadDb()
	if err != nil {
		return err
	}

	tasks := sortedTaskList()

	Header()
	for _, task := range tasks {
		task.Summary()
	}

	return nil
}
<commit_msg>Add filters for task list<commit_after>package task

import (
	"sort"
	"time"

	"nirenjan.org/overlord/internal/cmds/cli"
	"nirenjan.org/overlord/internal/log"
)

type TaskList []Task

func (tl TaskList) Len() int {
	return len(tl)
}

func (tl TaskList) Swap(i, j int) {
	tl[i], tl[j] = tl[j], tl[i]
}

func (tl TaskList) Less(i, j int) bool {
	t1 := tl[i]
	t2 := tl[j]

	// If deferred, completed or deleted, these should be towards the end
	if t1.State >= Deferred || t2.State >= Deferred {
		if t1.State != t2.State {
			return t1.State < t2.State
		}
	}

	// Compare the dates using the Equal function
	if !t1.Due.Equal(t2.Due) {
		return t1.Due.Sub(t2.Due) < 0
	}

	// If priorities are unequal, use them
	if t1.Priority != t2.Priority {
		return t1.Priority < t2.Priority
	}

	// Priorities are still equal, sort by state
	if t1.State != t2.State {
		return t1.State < t2.State
	}

	// All else being equal, sort by creation date
	return t1.Created.Sub(t2.Created) < 0
}

func registerListHandler(root *cli.Command) error {
	// task list
	cmd := cli.Cmd{
		Command:   "list",
		Usage:     "[type]",
		BriefHelp: "list all pending tasks",
		LongHelp: `
List all pending tasks. This includes tasks that are overdue, due shortly,
in progress (but not due shortly), and tasks that haven't been started.
`,
		Handler:    listHandler,
		Args:       cli.AtMost,
		Count:      1,
		Subcommand: "Task Types",
	}

	taskList, err := cli.RegisterCommandGroup(root, cmd)
	if err != nil {
		return err
	}

	// task list pending
	// This is the same as task list, so just change the relevant fields
	cmd.Command = "pending"
	cmd.Usage = " "
	cmd.Args = cli.None

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list overdue
	cmd = cli.Cmd{
		Command:   "overdue",
		Usage:     " ",
		BriefHelp: "list all overdue tasks",
		LongHelp: `
List all tasks that are past their due date, ordered by priority.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list due
	cmd = cli.Cmd{
		Command:   "due",
		Usage:     " ",
		BriefHelp: "list all tasks due shortly",
		LongHelp: `
List all tasks that are due within the next week, ordered by the due
date, then by their priority.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list in-progress
	cmd = cli.Cmd{
		Command:   "in-progress",
		Usage:     " ",
		BriefHelp: "list all tasks that are in progress",
		LongHelp: `
List all tasks that are currently in progress, ordered by the due date
and then by the priority.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list completed
	cmd = cli.Cmd{
		Command:   "completed",
		Usage:     " ",
		BriefHelp: "list all completed tasks",
		LongHelp: `
List all tasks that are completed.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list deleted
	cmd = cli.Cmd{
		Command:   "deleted",
		Usage:     " ",
		BriefHelp: "list all deleted tasks",
		LongHelp: `
List all tasks that are deleted.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list blocked
	cmd = cli.Cmd{
		Command:   "blocked",
		Usage:     " ",
		BriefHelp: "list all blocked tasks",
		LongHelp: `
List all tasks that are blocked.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list deferred
	cmd = cli.Cmd{
		Command:   "deferred",
		Usage:     " ",
		BriefHelp: "list all deferred tasks",
		LongHelp: `
List all tasks that are deferred.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	// task list all
	cmd = cli.Cmd{
		Command:   "all",
		Usage:     " ",
		BriefHelp: "list all tasks",
		LongHelp: `
List all tasks, including deferred, completed and deleted ones.
`,
		Handler: listHandler,
	}

	_, err = cli.RegisterCommand(taskList, cmd)
	if err != nil {
		return err
	}

	return nil
}

func sortedTaskList() TaskList {
	tasks := make(TaskList, len(DB))
	i := 0
	for _, task := range DB {
		tasks[i] = task
		i++
	}

	sort.Sort(tasks)
	return tasks
}

func listHandler(cmd *cli.Command, args []string) error {
	err := LoadDb()
	if err != nil {
		return err
	}

	log.Debug(cmd)
	log.Debug(args)

	tasks := sortedTaskList()

	Header()
	for _, task := range tasks {
		if task.Filter(args[0]) {
			task.Summary()
		}
	}

	return nil
}

func (t *Task) Filter(filter string) bool {
	switch filter {
	case "pending", "list":
		return t.State < Deferred

	case "in-progress":
		return t.State == InProgress

	case "overdue":
		return t.State < Deferred && time.Until(t.Due) <= 0

	case "due":
		if t.State < Deferred {
			due := time.Until(t.Due)
			return due > 0 && due < 96*time.Hour
		} else {
			return false
		}

	case "blocked":
		return t.State == Blocked

	case "completed":
		return t.State == Completed

	case "deferred":
		return t.State == Deferred

	case "deleted":
		return t.State == Deleted
	}

	return true
}
<|endoftext|>


<commit_before>package iterator

import "github.com/kezhuw/leveldb/internal/keys"

type rangeIterator struct {
	cmp    keys.Comparer
	iter   Iterator
	start  []byte
	limit  []byte
	valid  bool
	seeked bool
}

func (it *rangeIterator) checkStart(valid bool) bool {
	if valid && it.cmp.Compare(it.iter.Key(), it.start) >= 0 {
		it.valid = true
		return true
	}
	it.valid = false
	return false
}

func (it *rangeIterator) checkLimit(valid bool) bool {
	if valid && it.cmp.Compare(it.iter.Key(), it.limit) < 0 {
		it.valid = true
		return true
	}
	it.valid = false
	return false
}

func (it *rangeIterator) First() bool {
	it.seeked = true
	return it.checkLimit(it.iter.Seek(it.start))
}

func (it *rangeIterator) Last() bool {
	it.seeked = true
	switch {
	case it.iter.Seek(it.limit):
		for it.iter.Prev() {
			if it.cmp.Compare(it.iter.Key(), it.limit) < 0 {
				return it.checkStart(true)
			}
		}
	case it.iter.Last():
		// There are two reasons to fall in this case statement:
		// * Iterator has no elements greater than or equal to limit.
		// * Error happens in seeking. In this case, possibility exists
		//   that the last element exceed limit. So we iterate backward
		//   if necessary.
		for it.cmp.Compare(it.iter.Key(), it.limit) >= 0 {
			if !it.iter.Prev() {
				it.valid = false
				return false
			}
		}
		return it.checkStart(true)
	}
	it.valid = false
	return false
}

func (it *rangeIterator) Next() bool {
	switch {
	case !it.seeked:
		return it.First()
	case it.valid:
		return it.checkLimit(it.iter.Next())
	}
	return false
}

func (it *rangeIterator) Prev() bool {
	switch {
	case !it.seeked:
		return it.Last()
	case it.valid:
		return it.checkStart(it.iter.Prev())
	}
	return false
}

func (it *rangeIterator) Seek(target []byte) bool {
	it.seeked = true
	switch {
	case it.cmp.Compare(target, it.start) < 0:
		target = it.start
	case it.cmp.Compare(target, it.limit) >= 0:
		it.valid = false
		return false
	}
	return it.checkLimit(it.iter.Seek(target))
}

func (it *rangeIterator) Valid() bool {
	return it.valid
}

func (it *rangeIterator) Key() []byte {
	if it.valid {
		return it.iter.Key()
	}
	return nil
}

func (it *rangeIterator) Value() []byte {
	if it.valid {
		return it.iter.Value()
	}
	return nil
}

func (it *rangeIterator) Err() error {
	return it.iter.Err()
}

func (it *rangeIterator) Release() error {
	return it.iter.Release()
}

// NewRangeIterator creates a range iterator for keys in range [start, limit).
// Nil or empty start or limit act as no limitation in corresponding end. The
// resulting iterator implements semantics the exported Iterator interface
// defines. This means that if Next/Prev is the first seek method called, they
// act as First/Last respectively.
func NewRangeIterator(start, limit []byte, cmp keys.Comparer, it Iterator) Iterator {
	switch {
	case len(start) == 0 && len(limit) == 0:
		return it
	case len(limit) == 0:
		return newStartIterator(start, cmp, it)
	case len(start) == 0:
		return newLimitIterator(limit, cmp, it)
	case cmp.Compare(start, limit) >= 0:
		return empty
	}
	return &rangeIterator{cmp: cmp, iter: it, start: start, limit: limit}
}
<commit_msg>Wrap empty interval in range iterator for releasing<commit_after>package iterator

import "github.com/kezhuw/leveldb/internal/keys"

type rangeIterator struct {
	cmp    keys.Comparer
	iter   Iterator
	start  []byte
	limit  []byte
	valid  bool
	seeked bool
}

func (it *rangeIterator) checkStart(valid bool) bool {
	if valid && it.cmp.Compare(it.iter.Key(), it.start) >= 0 {
		it.valid = true
		return true
	}
	it.valid = false
	return false
}

func (it *rangeIterator) checkLimit(valid bool) bool {
	if valid && it.cmp.Compare(it.iter.Key(), it.limit) < 0 {
		it.valid = true
		return true
	}
	it.valid = false
	return false
}

func (it *rangeIterator) First() bool {
	it.seeked = true
	return it.checkLimit(it.iter.Seek(it.start))
}

func (it *rangeIterator) Last() bool {
	it.seeked = true
	switch {
	case it.iter.Seek(it.limit):
		for it.iter.Prev() {
			if it.cmp.Compare(it.iter.Key(), it.limit) < 0 {
				return it.checkStart(true)
			}
		}
	case it.iter.Last():
		// There are two reasons to fall in this case statement:
		// * Iterator has no elements greater than or equal to limit.
		// * Error happens in seeking. In this case, possibility exists
		//   that the last element exceed limit. So we iterate backward
		//   if necessary.
		for it.cmp.Compare(it.iter.Key(), it.limit) >= 0 {
			if !it.iter.Prev() {
				it.valid = false
				return false
			}
		}
		return it.checkStart(true)
	}
	it.valid = false
	return false
}

func (it *rangeIterator) Next() bool {
	switch {
	case !it.seeked:
		return it.First()
	case it.valid:
		return it.checkLimit(it.iter.Next())
	}
	return false
}

func (it *rangeIterator) Prev() bool {
	switch {
	case !it.seeked:
		return it.Last()
	case it.valid:
		return it.checkStart(it.iter.Prev())
	}
	return false
}

func (it *rangeIterator) Seek(target []byte) bool {
	it.seeked = true
	switch {
	case it.cmp.Compare(target, it.start) < 0:
		target = it.start
	case it.cmp.Compare(target, it.limit) >= 0:
		it.valid = false
		return false
	}
	return it.checkLimit(it.iter.Seek(target))
}

func (it *rangeIterator) Valid() bool {
	return it.valid
}

func (it *rangeIterator) Key() []byte {
	if it.valid {
		return it.iter.Key()
	}
	return nil
}

func (it *rangeIterator) Value() []byte {
	if it.valid {
		return it.iter.Value()
	}
	return nil
}

func (it *rangeIterator) Err() error {
	return it.iter.Err()
}

func (it *rangeIterator) Release() error {
	return it.iter.Release()
}

// NewRangeIterator creates a range iterator for keys in range [start, limit).
// Nil or empty start or limit act as no limitation in corresponding end. The
// resulting iterator implements semantics the exported Iterator interface
// defines. This means that if Next/Prev is the first seek method called, they
// act as First/Last respectively.
func NewRangeIterator(start, limit []byte, cmp keys.Comparer, it Iterator) Iterator {
	switch {
	case len(start) == 0 && len(limit) == 0:
		return it
	case len(limit) == 0:
		return newStartIterator(start, cmp, it)
	case len(start) == 0:
		return newLimitIterator(limit, cmp, it)
	}
	return &rangeIterator{cmp: cmp, iter: it, start: start, limit: limit}
}
<|endoftext|>


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

package cache

import (
	"context"
	"fmt"
	"go/types"
	"sort"
	"strings"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/event"
	"golang.org/x/tools/internal/lsp/debug/tag"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/packagesinternal"
	"golang.org/x/tools/internal/span"
	errors "golang.org/x/xerrors"
)

type metadata struct {
	id              packageID
	pkgPath         packagePath
	name            string
	goFiles         []span.URI
	compiledGoFiles []span.URI
	forTest         packagePath
	typesSizes      types.Sizes
	errors          []packages.Error
	deps            []packageID
	missingDeps     map[packagePath]struct{}
	module          *packages.Module

	// config is the *packages.Config associated with the loaded package.
	config *packages.Config
}

func (s *snapshot) load(ctx context.Context, scopes ...interface{}) error {
	var query []string
	var containsDir bool // for logging
	for _, scope := range scopes {
		switch scope := scope.(type) {
		case packagePath:
			if scope == "command-line-arguments" {
				panic("attempted to load command-line-arguments")
			}
			// The only time we pass package paths is when we're doing a
			// partial workspace load. In those cases, the paths came back from
			// go list and should already be GOPATH-vendorized when appropriate.
			query = append(query, string(scope))
		case fileURI:
			query = append(query, fmt.Sprintf("file=%s", span.URI(scope).Filename()))
		case directoryURI:
			filename := span.URI(scope).Filename()
			q := fmt.Sprintf("%s/...", filename)
			// Simplify the query if it will be run in the requested directory.
			// This ensures compatibility with Go 1.12 that doesn't allow
			// <directory>/... in GOPATH mode.
			if s.view.folder.Filename() == filename {
				q = "./..."
			}
			query = append(query, q)
		case viewLoadScope:
			// If we are outside of GOPATH, a module, or some other known
			// build system, don't load subdirectories.
			if !s.view.hasValidBuildConfiguration {
				query = append(query, "./")
			} else {
				query = append(query, "./...")
			}
		default:
			panic(fmt.Sprintf("unknown scope type %T", scope))
		}
		switch scope.(type) {
		case directoryURI, viewLoadScope:
			containsDir = true
		}
	}
	sort.Strings(query) // for determinism

	ctx, done := event.Start(ctx, "cache.view.load", tag.Query.Of(query))
	defer done()

	cfg := s.Config(ctx)
	pkgs, err := packages.Load(cfg, query...)

	// If the context was canceled, return early. Otherwise, we might be
	// type-checking an incomplete result. Check the context directly,
	// because go/packages adds extra information to the error.
	if ctx.Err() != nil {
		return ctx.Err()
	}
	if err != nil {
		// Match on common error messages. This is really hacky, but I'm not sure
		// of any better way. This can be removed when golang/go#39164 is resolved.
		if strings.Contains(err.Error(), "inconsistent vendoring") {
			return source.InconsistentVendoring
		}
		event.Error(ctx, "go/packages.Load", err, tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
	} else {
		event.Log(ctx, "go/packages.Load", tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
	}
	if len(pkgs) == 0 {
		return err
	}

	for _, pkg := range pkgs {
		if !containsDir || s.view.Options().VerboseOutput {
			event.Log(ctx, "go/packages.Load", tag.Snapshot.Of(s.ID()), tag.PackagePath.Of(pkg.PkgPath), tag.Files.Of(pkg.CompiledGoFiles))
		}
		// Ignore packages with no sources, since we will never be able to
		// correctly invalidate that metadata.
		if len(pkg.GoFiles) == 0 && len(pkg.CompiledGoFiles) == 0 {
			continue
		}
		// Special case for the builtin package, as it has no dependencies.
		if pkg.PkgPath == "builtin" {
			if err := s.view.buildBuiltinPackage(ctx, pkg.GoFiles); err != nil {
				return err
			}
			continue
		}
		// Skip test main packages.
		if isTestMain(pkg, s.view.gocache) {
			continue
		}
		// Set the metadata for this package.
		m, err := s.setMetadata(ctx, packagePath(pkg.PkgPath), pkg, cfg, map[packageID]struct{}{})
		if err != nil {
			return err
		}
		if _, err := s.buildPackageHandle(ctx, m.id, source.ParseFull); err != nil {
			return err
		}
	}
	// Rebuild the import graph when the metadata is updated.
	s.clearAndRebuildImportGraph()

	return nil
}

func (s *snapshot) setMetadata(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) (*metadata, error) {
	id := packageID(pkg.ID)
	if _, ok := seen[id]; ok {
		return nil, errors.Errorf("import cycle detected: %q", id)
	}
	// Recreate the metadata rather than reusing it to avoid locking.
	m := &metadata{
		id:         id,
		pkgPath:    pkgPath,
		name:       pkg.Name,
		forTest:    packagePath(packagesinternal.GetForTest(pkg)),
		typesSizes: pkg.TypesSizes,
		errors:     pkg.Errors,
		config:     cfg,
		module:     pkg.Module,
	}

	for _, filename := range pkg.CompiledGoFiles {
		uri := span.URIFromPath(filename)
		m.compiledGoFiles = append(m.compiledGoFiles, uri)
		s.addID(uri, m.id)
	}
	for _, filename := range pkg.GoFiles {
		uri := span.URIFromPath(filename)
		m.goFiles = append(m.goFiles, uri)
		s.addID(uri, m.id)
	}

	copied := map[packageID]struct{}{
		id: {},
	}
	for k, v := range seen {
		copied[k] = v
	}
	for importPath, importPkg := range pkg.Imports {
		importPkgPath := packagePath(importPath)
		importID := packageID(importPkg.ID)

		m.deps = append(m.deps, importID)

		// Don't remember any imports with significant errors.
		if importPkgPath != "unsafe" && len(importPkg.CompiledGoFiles) == 0 {
			if m.missingDeps == nil {
				m.missingDeps = make(map[packagePath]struct{})
			}
			m.missingDeps[importPkgPath] = struct{}{}
			continue
		}
		if s.getMetadata(importID) == nil {
			if _, err := s.setMetadata(ctx, importPkgPath, importPkg, cfg, copied); err != nil {
				event.Error(ctx, "error in dependency", err)
			}
		}
	}

	// Add the metadata to the cache.
	s.mu.Lock()
	defer s.mu.Unlock()

	// TODO: We should make sure not to set duplicate metadata,
	// and instead panic here. This can be done by making sure not to
	// reset metadata information for packages we've already seen.
	if original, ok := s.metadata[m.id]; ok {
		m = original
	} else {
		s.metadata[m.id] = m
	}

	// Set the workspace packages. If any of the package's files belong to the
	// view, then the package is considered to be a workspace package.
	for _, uri := range append(m.compiledGoFiles, m.goFiles...) {
		// If the package's files are in this view, mark it as a workspace package.
		if s.view.contains(uri) {
			// A test variant of a package can only be loaded directly by loading
			// the non-test variant with -test. Track the import path of the non-test variant.
			if m.forTest != "" {
				s.workspacePackages[m.id] = m.forTest
			} else {
				s.workspacePackages[m.id] = pkgPath
			}
			break
		}
	}
	return m, nil
}

func isTestMain(pkg *packages.Package, gocache string) bool {
	// Test mains must have an import path that ends with ".test".
	if !strings.HasSuffix(pkg.PkgPath, ".test") {
		return false
	}
	// Test main packages are always named "main".
	if pkg.Name != "main" {
		return false
	}
	// Test mains always have exactly one GoFile that is in the build cache.
	if len(pkg.GoFiles) > 1 {
		return false
	}
	if !strings.HasPrefix(pkg.GoFiles[0], gocache) {
		return false
	}
	return true
}
<commit_msg>internal/lsp/cache: intermediate test variants aren't workspace packages<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"context"
	"fmt"
	"go/types"
	"sort"
	"strings"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/event"
	"golang.org/x/tools/internal/lsp/debug/tag"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/packagesinternal"
	"golang.org/x/tools/internal/span"
	errors "golang.org/x/xerrors"
)

type metadata struct {
	id              packageID
	pkgPath         packagePath
	name            string
	goFiles         []span.URI
	compiledGoFiles []span.URI
	forTest         packagePath
	typesSizes      types.Sizes
	errors          []packages.Error
	deps            []packageID
	missingDeps     map[packagePath]struct{}
	module          *packages.Module

	// config is the *packages.Config associated with the loaded package.
	config *packages.Config
}

func (s *snapshot) load(ctx context.Context, scopes ...interface{}) error {
	var query []string
	var containsDir bool // for logging
	for _, scope := range scopes {
		switch scope := scope.(type) {
		case packagePath:
			if scope == "command-line-arguments" {
				panic("attempted to load command-line-arguments")
			}
			// The only time we pass package paths is when we're doing a
			// partial workspace load. In those cases, the paths came back from
			// go list and should already be GOPATH-vendorized when appropriate.
			query = append(query, string(scope))
		case fileURI:
			query = append(query, fmt.Sprintf("file=%s", span.URI(scope).Filename()))
		case directoryURI:
			filename := span.URI(scope).Filename()
			q := fmt.Sprintf("%s/...", filename)
			// Simplify the query if it will be run in the requested directory.
			// This ensures compatibility with Go 1.12 that doesn't allow
			// <directory>/... in GOPATH mode.
			if s.view.folder.Filename() == filename {
				q = "./..."
			}
			query = append(query, q)
		case viewLoadScope:
			// If we are outside of GOPATH, a module, or some other known
			// build system, don't load subdirectories.
			if !s.view.hasValidBuildConfiguration {
				query = append(query, "./")
			} else {
				query = append(query, "./...")
			}
		default:
			panic(fmt.Sprintf("unknown scope type %T", scope))
		}
		switch scope.(type) {
		case directoryURI, viewLoadScope:
			containsDir = true
		}
	}
	sort.Strings(query) // for determinism

	ctx, done := event.Start(ctx, "cache.view.load", tag.Query.Of(query))
	defer done()

	cfg := s.Config(ctx)
	pkgs, err := packages.Load(cfg, query...)

	// If the context was canceled, return early. Otherwise, we might be
	// type-checking an incomplete result. Check the context directly,
	// because go/packages adds extra information to the error.
	if ctx.Err() != nil {
		return ctx.Err()
	}
	if err != nil {
		// Match on common error messages. This is really hacky, but I'm not sure
		// of any better way. This can be removed when golang/go#39164 is resolved.
		if strings.Contains(err.Error(), "inconsistent vendoring") {
			return source.InconsistentVendoring
		}
		event.Error(ctx, "go/packages.Load", err, tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
	} else {
		event.Log(ctx, "go/packages.Load", tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
	}
	if len(pkgs) == 0 {
		return err
	}

	for _, pkg := range pkgs {
		if !containsDir || s.view.Options().VerboseOutput {
			event.Log(ctx, "go/packages.Load", tag.Snapshot.Of(s.ID()), tag.PackagePath.Of(pkg.PkgPath), tag.Files.Of(pkg.CompiledGoFiles))
		}
		// Ignore packages with no sources, since we will never be able to
		// correctly invalidate that metadata.
		if len(pkg.GoFiles) == 0 && len(pkg.CompiledGoFiles) == 0 {
			continue
		}
		// Special case for the builtin package, as it has no dependencies.
		if pkg.PkgPath == "builtin" {
			if err := s.view.buildBuiltinPackage(ctx, pkg.GoFiles); err != nil {
				return err
			}
			continue
		}
		// Skip test main packages.
		if isTestMain(pkg, s.view.gocache) {
			continue
		}
		// Set the metadata for this package.
		m, err := s.setMetadata(ctx, packagePath(pkg.PkgPath), pkg, cfg, map[packageID]struct{}{})
		if err != nil {
			return err
		}
		if _, err := s.buildPackageHandle(ctx, m.id, source.ParseFull); err != nil {
			return err
		}
	}
	// Rebuild the import graph when the metadata is updated.
	s.clearAndRebuildImportGraph()

	return nil
}

func (s *snapshot) setMetadata(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) (*metadata, error) {
	id := packageID(pkg.ID)
	if _, ok := seen[id]; ok {
		return nil, errors.Errorf("import cycle detected: %q", id)
	}
	// Recreate the metadata rather than reusing it to avoid locking.
	m := &metadata{
		id:         id,
		pkgPath:    pkgPath,
		name:       pkg.Name,
		forTest:    packagePath(packagesinternal.GetForTest(pkg)),
		typesSizes: pkg.TypesSizes,
		errors:     pkg.Errors,
		config:     cfg,
		module:     pkg.Module,
	}

	for _, filename := range pkg.CompiledGoFiles {
		uri := span.URIFromPath(filename)
		m.compiledGoFiles = append(m.compiledGoFiles, uri)
		s.addID(uri, m.id)
	}
	for _, filename := range pkg.GoFiles {
		uri := span.URIFromPath(filename)
		m.goFiles = append(m.goFiles, uri)
		s.addID(uri, m.id)
	}

	copied := map[packageID]struct{}{
		id: {},
	}
	for k, v := range seen {
		copied[k] = v
	}
	for importPath, importPkg := range pkg.Imports {
		importPkgPath := packagePath(importPath)
		importID := packageID(importPkg.ID)

		m.deps = append(m.deps, importID)

		// Don't remember any imports with significant errors.
		if importPkgPath != "unsafe" && len(importPkg.CompiledGoFiles) == 0 {
			if m.missingDeps == nil {
				m.missingDeps = make(map[packagePath]struct{})
			}
			m.missingDeps[importPkgPath] = struct{}{}
			continue
		}
		if s.getMetadata(importID) == nil {
			if _, err := s.setMetadata(ctx, importPkgPath, importPkg, cfg, copied); err != nil {
				event.Error(ctx, "error in dependency", err)
			}
		}
	}

	// Add the metadata to the cache.
	s.mu.Lock()
	defer s.mu.Unlock()

	// TODO: We should make sure not to set duplicate metadata,
	// and instead panic here. This can be done by making sure not to
	// reset metadata information for packages we've already seen.
	if original, ok := s.metadata[m.id]; ok {
		m = original
	} else {
		s.metadata[m.id] = m
	}

	// Set the workspace packages. If any of the package's files belong to the
	// view, then the package is considered to be a workspace package.
	for _, uri := range append(m.compiledGoFiles, m.goFiles...) {
		if !s.view.contains(uri) {
			continue
		}

		// The package's files are in this view. It may be a workspace package.
		switch m.forTest {
		case "":
			// A normal package.
			s.workspacePackages[m.id] = pkgPath
		case m.pkgPath:
			// The test variant of some workspace package. To load it, we need to
			// load the non-test variant with -test.
			s.workspacePackages[m.id] = m.forTest
		default:
			// A test variant of some intermediate package. We don't care about it.
		}
	}
	return m, nil
}

func isTestMain(pkg *packages.Package, gocache string) bool {
	// Test mains must have an import path that ends with ".test".
	if !strings.HasSuffix(pkg.PkgPath, ".test") {
		return false
	}
	// Test main packages are always named "main".
	if pkg.Name != "main" {
		return false
	}
	// Test mains always have exactly one GoFile that is in the build cache.
	if len(pkg.GoFiles) > 1 {
		return false
	}
	if !strings.HasPrefix(pkg.GoFiles[0], gocache) {
		return false
	}
	return true
}
<|endoftext|>


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

package lsp

import (
	"bytes"
	"fmt"
	"sort"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
)

func toProtocolCompletionItems(candidates []source.CompletionItem, prefix string, pos protocol.Position, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem {
	insertTextFormat := protocol.PlainTextTextFormat
	if snippetsSupported {
		insertTextFormat = protocol.SnippetTextFormat
	}
	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].Score > candidates[j].Score
	})
	items := []protocol.CompletionItem{}
	for i, candidate := range candidates {
		// Matching against the label.
		if !strings.HasPrefix(candidate.Label, prefix) {
			continue
		}
		insertText, triggerSignatureHelp := labelToProtocolSnippets(candidate.Label, candidate.Kind, insertTextFormat, signatureHelpEnabled)
		if strings.HasPrefix(insertText, prefix) {
			insertText = insertText[len(prefix):]
		}
		item := protocol.CompletionItem{
			Label:            candidate.Label,
			Detail:           candidate.Detail,
			Kind:             toProtocolCompletionItemKind(candidate.Kind),
			InsertTextFormat: protocol.PlainTextTextFormat,
			TextEdit: &protocol.TextEdit{
				NewText: insertText,
				Range: protocol.Range{
					Start: pos,
					End:   pos,
				},
			},
			// InsertText is deprecated in favor of TextEdit.
			InsertText: insertText,
			// This is a hack so that the client sorts completion results in the order
			// according to their score. This can be removed upon the resolution of
			// https://github.com/Microsoft/language-server-protocol/issues/348.
			SortText: fmt.Sprintf("%05d", i),
		}
		// If we are completing a function, we should trigger signature help if possible.
		if triggerSignatureHelp && signatureHelpEnabled {
			item.Command = &protocol.Command{
				Command: "editor.action.triggerParameterHints",
			}
		}
		items = append(items, item)
	}
	return items
}

func toProtocolCompletionItemKind(kind source.CompletionItemKind) protocol.CompletionItemKind {
	switch kind {
	case source.InterfaceCompletionItem:
		return protocol.InterfaceCompletion
	case source.StructCompletionItem:
		return protocol.StructCompletion
	case source.TypeCompletionItem:
		return protocol.TypeParameterCompletion // ??
	case source.ConstantCompletionItem:
		return protocol.ConstantCompletion
	case source.FieldCompletionItem:
		return protocol.FieldCompletion
	case source.ParameterCompletionItem, source.VariableCompletionItem:
		return protocol.VariableCompletion
	case source.FunctionCompletionItem:
		return protocol.FunctionCompletion
	case source.MethodCompletionItem:
		return protocol.MethodCompletion
	case source.PackageCompletionItem:
		return protocol.ModuleCompletion // ??
	default:
		return protocol.TextCompletion
	}
}

func labelToProtocolSnippets(label string, kind source.CompletionItemKind, insertTextFormat protocol.InsertTextFormat, signatureHelpEnabled bool) (string, bool) {
	switch kind {
	case source.ConstantCompletionItem:
		// The label for constants is of the format "<identifier> = <value>".
		// We should not insert the " = <value>" part of the label.
		if i := strings.Index(label, " ="); i >= 0 {
			return label[:i], false
		}
	case source.FunctionCompletionItem, source.MethodCompletionItem:
		var trimmed, params string
		if i := strings.Index(label, "("); i >= 0 {
			trimmed = label[:i]
			params = strings.Trim(label[i:], "()")
		}
		if params == "" || trimmed == "" {
			return label, true
		}
		// Don't add parameters or parens for the plaintext insert format.
		if insertTextFormat == protocol.PlainTextTextFormat {
			return trimmed, true
		}
		// If we do have signature help enabled, the user can see parameters as
		// they type in the function, so we just return empty parentheses.
		if signatureHelpEnabled {
			return trimmed + "($1)", true
		}
		// If signature help is not enabled, we should give the user parameters
		// that they can tab through. The insert text format follows the
		// specification defined by Microsoft for LSP. The "$", "}, and "\"
		// characters should be escaped.
		r := strings.NewReplacer(
			`\`, `\\`,
			`}`, `\}`,
			`$`, `\$`,
		)
		b := bytes.NewBufferString(trimmed)
		b.WriteByte('(')
		for i, p := range strings.Split(params, ",") {
			if i != 0 {
				b.WriteString(", ")
			}
			fmt.Fprintf(b, "${%v:%v}", i+1, r.Replace(strings.Trim(p, " ")))
		}
		b.WriteByte(')')
		return b.String(), false

	}
	return label, false
}
<commit_msg>internal/lsp: stop providing insertText for completion items<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsp

import (
	"bytes"
	"fmt"
	"sort"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
)

func toProtocolCompletionItems(candidates []source.CompletionItem, prefix string, pos protocol.Position, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem {
	insertTextFormat := protocol.PlainTextTextFormat
	if snippetsSupported {
		insertTextFormat = protocol.SnippetTextFormat
	}
	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].Score > candidates[j].Score
	})
	items := []protocol.CompletionItem{}
	for i, candidate := range candidates {
		// Matching against the label.
		if !strings.HasPrefix(candidate.Label, prefix) {
			continue
		}
		// InsertText is deprecated in favor of TextEdits.
		// TODO(rstambler): Remove this logic when we are confident that we no
		// longer need to support it.
		insertText, triggerSignatureHelp := labelToProtocolSnippets(candidate.Label, candidate.Kind, insertTextFormat, signatureHelpEnabled)
		if strings.HasPrefix(insertText, prefix) {
			insertText = insertText[len(prefix):]
		}
		item := protocol.CompletionItem{
			Label:  candidate.Label,
			Detail: candidate.Detail,
			Kind:   toProtocolCompletionItemKind(candidate.Kind),
			TextEdit: &protocol.TextEdit{
				NewText: insertText,
				Range: protocol.Range{
					Start: pos,
					End:   pos,
				},
			},
			// This is a hack so that the client sorts completion results in the order
			// according to their score. This can be removed upon the resolution of
			// https://github.com/Microsoft/language-server-protocol/issues/348.
			SortText: fmt.Sprintf("%05d", i),
		}
		// If we are completing a function, we should trigger signature help if possible.
		if triggerSignatureHelp && signatureHelpEnabled {
			item.Command = &protocol.Command{
				Command: "editor.action.triggerParameterHints",
			}
		}
		items = append(items, item)
	}
	return items
}

func toProtocolCompletionItemKind(kind source.CompletionItemKind) protocol.CompletionItemKind {
	switch kind {
	case source.InterfaceCompletionItem:
		return protocol.InterfaceCompletion
	case source.StructCompletionItem:
		return protocol.StructCompletion
	case source.TypeCompletionItem:
		return protocol.TypeParameterCompletion // ??
	case source.ConstantCompletionItem:
		return protocol.ConstantCompletion
	case source.FieldCompletionItem:
		return protocol.FieldCompletion
	case source.ParameterCompletionItem, source.VariableCompletionItem:
		return protocol.VariableCompletion
	case source.FunctionCompletionItem:
		return protocol.FunctionCompletion
	case source.MethodCompletionItem:
		return protocol.MethodCompletion
	case source.PackageCompletionItem:
		return protocol.ModuleCompletion // ??
	default:
		return protocol.TextCompletion
	}
}

func labelToProtocolSnippets(label string, kind source.CompletionItemKind, insertTextFormat protocol.InsertTextFormat, signatureHelpEnabled bool) (string, bool) {
	switch kind {
	case source.ConstantCompletionItem:
		// The label for constants is of the format "<identifier> = <value>".
		// We should not insert the " = <value>" part of the label.
		if i := strings.Index(label, " ="); i >= 0 {
			return label[:i], false
		}
	case source.FunctionCompletionItem, source.MethodCompletionItem:
		var trimmed, params string
		if i := strings.Index(label, "("); i >= 0 {
			trimmed = label[:i]
			params = strings.Trim(label[i:], "()")
		}
		if params == "" || trimmed == "" {
			return label, true
		}
		// Don't add parameters or parens for the plaintext insert format.
		if insertTextFormat == protocol.PlainTextTextFormat {
			return trimmed, true
		}
		// If we do have signature help enabled, the user can see parameters as
		// they type in the function, so we just return empty parentheses.
		if signatureHelpEnabled {
			return trimmed + "($1)", true
		}
		// If signature help is not enabled, we should give the user parameters
		// that they can tab through. The insert text format follows the
		// specification defined by Microsoft for LSP. The "$", "}, and "\"
		// characters should be escaped.
		r := strings.NewReplacer(
			`\`, `\\`,
			`}`, `\}`,
			`$`, `\$`,
		)
		b := bytes.NewBufferString(trimmed)
		b.WriteByte('(')
		for i, p := range strings.Split(params, ",") {
			if i != 0 {
				b.WriteString(", ")
			}
			fmt.Fprintf(b, "${%v:%v}", i+1, r.Replace(strings.Trim(p, " ")))
		}
		b.WriteByte(')')
		return b.String(), false

	}
	return label, false
}
<|endoftext|>


<commit_before>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE file.

package gohg

import (
	"errors"
	"fmt"
	"path/filepath"
)

type initOpts struct {
	Cwd
	Destpath
	Insecure
	Mq
	Remote
	Ssh
	Debug
	Profile
	Traceback
}

func (cmd *initOpts) String() string {
	return fmt.Sprintf(
		"initOpts = {\n    filepath: (%T) %q\n    Mq: (%T) %t\n"+
			"    Cwd: (%T) %t\n"+
			"    debug: (%T) %t\n    traceback: (%T) %t\n    profile: (%T) %t\n}\n",
		cmd.Destpath, cmd.Destpath, cmd.Mq, cmd.Mq, cmd.Cwd, cmd.Cwd,
		cmd.Debug, cmd.Debug, cmd.Traceback, cmd.Traceback, cmd.Profile, cmd.Profile)
}

// TODO	Implement the flags for hg init.

// Init provides the 'hg init' command.
//
// Be aware of the fact that it cannot be used to initialize the repo you want
// the (current) Hg CS to work on, as the Hg CS requires an existing repo.
// But Init() can be used to create any new repo outside the one the Hg CS is
// running for.
func (hgcl *HgClient) Init(opts ...optionAdder) error {
	cmdOpts := new(initOpts)
	// apply gohg defaults (that differ from type default)
	cmdOpts.Destpath = "."
	hgcmd, err := hgcl.buildCommand("init", cmdOpts, opts)
	if err != nil {
		return err
	}

	fa, err := filepath.Abs(string(cmdOpts.Destpath))
	if err != nil {
		return fmt.Errorf("Init() -> filepath.Abs(): %s", err)
	}
	if (cmdOpts.Destpath == "" || cmdOpts.Destpath == "." || fa == hgcl.RepoRoot()) && cmdOpts.Mq == false {
		return errors.New("HgClient.Init: path for new repo must be different" +
			" from the Command Server repo path")
	}

	_, err = hgcl.runcommand(&hgcmd)
	return err
}
<commit_msg>init: removed gohg default value for Destpath option<commit_after>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE file.

package gohg

import (
	"errors"
	"fmt"
	"path/filepath"
)

type initOpts struct {
	Cwd
	Destpath
	Insecure
	Mq
	Remote
	Ssh
	Debug
	Profile
	Traceback
}

func (cmd *initOpts) String() string {
	return fmt.Sprintf(
		"initOpts = {\n    filepath: (%T) %q\n    Mq: (%T) %t\n"+
			"    Cwd: (%T) %t\n"+
			"    debug: (%T) %t\n    traceback: (%T) %t\n    profile: (%T) %t\n}\n",
		cmd.Destpath, cmd.Destpath, cmd.Mq, cmd.Mq, cmd.Cwd, cmd.Cwd,
		cmd.Debug, cmd.Debug, cmd.Traceback, cmd.Traceback, cmd.Profile, cmd.Profile)
}

// TODO	Implement the flags for hg init.

// Init provides the 'hg init' command.
//
// Be aware of the fact that it cannot be used to initialize the repo you want
// the (current) Hg CS to work on, as the Hg CS requires an existing repo.
// But Init() can be used to create any new repo outside the one the Hg CS is
// running for.
func (hgcl *HgClient) Init(opts ...optionAdder) error {
	cmdOpts := new(initOpts)
	hgcmd, err := hgcl.buildCommand("init", cmdOpts, opts)
	if err != nil {
		return err
	}

	fa, err := filepath.Abs(string(cmdOpts.Destpath))
	if err != nil {
		return fmt.Errorf("Init() -> filepath.Abs(): %s", err)
	}
	if (cmdOpts.Destpath == "" || cmdOpts.Destpath == "." || fa == hgcl.RepoRoot()) && cmdOpts.Mq == false {
		return errors.New("HgClient.Init: path for new repo must be different" +
			" from the Command Server repo path")
	}

	_, err = hgcl.runcommand(&hgcmd)
	return err
}
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

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

// Package main cmdline client for the Baruwa REST API
package main

import (
	"github.com/baruwa-enterprise/baruwa-go/api"
	"github.com/integrii/flaggy"
)

var (
	apiToken             string
	serverURL            string
	user                 *flaggy.Subcommand
	userGet              *flaggy.Subcommand
	userCreate           *flaggy.Subcommand
	userUpdate           *flaggy.Subcommand
	userDelete           *flaggy.Subcommand
	userAlias            *flaggy.Subcommand
	userAliasGet         *flaggy.Subcommand
	userAliasCreate      *flaggy.Subcommand
	userAliasUpdate      *flaggy.Subcommand
	userAliasDelete      *flaggy.Subcommand
	domain               *flaggy.Subcommand
	domainGet            *flaggy.Subcommand
	domainCreate         *flaggy.Subcommand
	domainUpdate         *flaggy.Subcommand
	domainDelete         *flaggy.Subcommand
	domainAlias          *flaggy.Subcommand
	domainAliasGet       *flaggy.Subcommand
	domainAliasCreate    *flaggy.Subcommand
	domainAliasUpdate    *flaggy.Subcommand
	domainAliasDelete    *flaggy.Subcommand
	domainDS             *flaggy.Subcommand
	domainDSGet          *flaggy.Subcommand
	domainDSCreate       *flaggy.Subcommand
	domainDSUpdate       *flaggy.Subcommand
	domainDSDelete       *flaggy.Subcommand
	userDS               *flaggy.Subcommand
	userDSGet            *flaggy.Subcommand
	userDSCreate         *flaggy.Subcommand
	userDSUpdate         *flaggy.Subcommand
	userDSDelete         *flaggy.Subcommand
	domainAS             *flaggy.Subcommand
	domainASGet          *flaggy.Subcommand
	domainASCreate       *flaggy.Subcommand
	domainASUpdate       *flaggy.Subcommand
	domainASDelete       *flaggy.Subcommand
	domainSM             *flaggy.Subcommand
	domainSMGet          *flaggy.Subcommand
	domainSMCreate       *flaggy.Subcommand
	domainSMUpdate       *flaggy.Subcommand
	domainSMDelete       *flaggy.Subcommand
	ldap                 *flaggy.Subcommand
	ldapGet              *flaggy.Subcommand
	ldapCreate           *flaggy.Subcommand
	ldapUpdate           *flaggy.Subcommand
	ldapDelete           *flaggy.Subcommand
	radius               *flaggy.Subcommand
	radiusGet            *flaggy.Subcommand
	radiusCreate         *flaggy.Subcommand
	radiusUpdate         *flaggy.Subcommand
	radiusDelete         *flaggy.Subcommand
	organization         *flaggy.Subcommand
	organizationGet      *flaggy.Subcommand
	organizationCreate   *flaggy.Subcommand
	organizationUpdate   *flaggy.Subcommand
	organizationDelete   *flaggy.Subcommand
	relay                *flaggy.Subcommand
	relayGet             *flaggy.Subcommand
	relayCreate          *flaggy.Subcommand
	relayUpdate          *flaggy.Subcommand
	relayDelete          *flaggy.Subcommand
	fallbackServer       *flaggy.Subcommand
	fallbackServerGet    *flaggy.Subcommand
	fallbackServerCreate *flaggy.Subcommand
	fallbackServerUpdate *flaggy.Subcommand
	fallbackServerDelete *flaggy.Subcommand
	organizationSM       *flaggy.Subcommand
	organizationSMGet    *flaggy.Subcommand
	organizationSMCreate *flaggy.Subcommand
	organizationSMUpdate *flaggy.Subcommand
	organizationSMDelete *flaggy.Subcommand
	organizations        *flaggy.Subcommand
	system               *flaggy.Subcommand
	users                *flaggy.Subcommand
	domains              *flaggy.Subcommand
	domainAliases        *flaggy.Subcommand
	userDSs              *flaggy.Subcommand
	domainASs            *flaggy.Subcommand
	domainDSs            *flaggy.Subcommand
	domainSMs            *flaggy.Subcommand
	fallbackServers      *flaggy.Subcommand
	organizationSMs      *flaggy.Subcommand
)

func init() {
	flaggy.SetName("baruwa")
	flaggy.SetDescription("A cmdline client for the Baruwa REST API.")
	flaggy.SetVersion(api.Version)
	user = flaggy.NewSubcommand("user")
	user.Description = "Account management"
	userGet = flaggy.NewSubcommand("show")
	userGet.Description = "Show account details"
	userCreate = flaggy.NewSubcommand("create")
	userCreate.Description = "Create account"
	userUpdate = flaggy.NewSubcommand("update")
	userUpdate.Description = "Update account"
	userDelete = flaggy.NewSubcommand("delete")
	userDelete.Description = "Delete account"

	userAlias = flaggy.NewSubcommand("alias")
	userAlias.Description = "Alias address management"
	userAliasGet = flaggy.NewSubcommand("show")
	userAliasGet.Description = "Show alias address details"
	userAliasCreate = flaggy.NewSubcommand("create")
	userAliasCreate.Description = "Create alias address"
	userAliasUpdate = flaggy.NewSubcommand("update")
	userAliasUpdate.Description = "Update alias address"
	userAliasDelete = flaggy.NewSubcommand("delete")
	userAliasDelete.Description = "Delete alias address"

	users = flaggy.NewSubcommand("users")
	users.Description = "List Accounts"

	domain = flaggy.NewSubcommand("domain")
	domain.Description = "Domain management"
	domainGet = flaggy.NewSubcommand("show")
	domainGet.Description = "Show domain details"
	domainCreate = flaggy.NewSubcommand("create")
	domainCreate.Description = "Create domain"
	domainUpdate = flaggy.NewSubcommand("update")
	domainUpdate.Description = "Update domain"
	domainDelete = flaggy.NewSubcommand("delete")
	domainDelete.Description = "Delete domain"

	domainAliases = flaggy.NewSubcommand("aliases")
	domainAliases.Description = "List domain aliases"

	domainAlias = flaggy.NewSubcommand("alias")
	domainAlias.Description = "Domain alias management"
	domainAliasGet = flaggy.NewSubcommand("show")
	domainAliasGet.Description = "Show domain alias details"
	domainAliasCreate = flaggy.NewSubcommand("create")
	domainAliasCreate.Description = "Create alias domain"
	domainAliasUpdate = flaggy.NewSubcommand("update")
	domainAliasUpdate.Description = "Update alias domain"
	domainAliasDelete = flaggy.NewSubcommand("delete")
	domainAliasDelete.Description = "Delete alias domain"

	domainDSs = flaggy.NewSubcommand("deliverservers")
	domainDSs.Description = "List domain delivery servers"

	domainDS = flaggy.NewSubcommand("deliverserver")
	domainDS.Description = "Delivery server management"
	domainDSGet = flaggy.NewSubcommand("show")
	domainDSGet.Description = "Show delivery server details"
	domainDSCreate = flaggy.NewSubcommand("create")
	domainDSCreate.Description = "Create delivery server"
	domainDSUpdate = flaggy.NewSubcommand("update")
	domainDSUpdate.Description = "Update delivery server"
	domainDSDelete = flaggy.NewSubcommand("delete")
	domainDSDelete.Description = "Delete delivery server"

	userDSs = flaggy.NewSubcommand("userdeliverservers")
	userDSs.Description = "List user delivery servers"

	userDS = flaggy.NewSubcommand("userdeliverserver")
	userDS.Description = "User delivery server management"
	userDSGet = flaggy.NewSubcommand("show")
	userDSGet.Description = "Show user delivery server details"
	userDSCreate = flaggy.NewSubcommand("create")
	userDSCreate.Description = "Create user delivery server"
	userDSUpdate = flaggy.NewSubcommand("update")
	userDSUpdate.Description = "Update user delivery server"
	userDSDelete = flaggy.NewSubcommand("delete")
	userDSDelete.Description = "Delete user delivery server"

	domains = flaggy.NewSubcommand("domains")
	domains.Description = "List domains"

	domainASs = flaggy.NewSubcommand("authsettings")
	domainASs.Description = "List authentication settings"

	domainAS = flaggy.NewSubcommand("authsetting")
	domainAS.Description = "Authentication settings management"
	domainASGet = flaggy.NewSubcommand("show")
	domainASGet.Description = "Show authentication settings details"
	domainASCreate = flaggy.NewSubcommand("create")
	domainASCreate.Description = "Create authentication settings"
	domainASUpdate = flaggy.NewSubcommand("update")
	domainASUpdate.Description = "Update authentication settings"
	domainASDelete = flaggy.NewSubcommand("delete")
	domainASDelete.Description = "Delete authentication settings"

	domainSMs = flaggy.NewSubcommand("smarthosts")
	domainSMs.Description = "List smarthosts"

	domainSM = flaggy.NewSubcommand("smarthost")
	domainSM.Description = "Smarthost management"
	domainSMGet = flaggy.NewSubcommand("show")
	domainSMGet.Description = "Show smarthost details"
	domainSMCreate = flaggy.NewSubcommand("create")
	domainSMCreate.Description = "Create smarthost"
	domainSMUpdate = flaggy.NewSubcommand("update")
	domainSMUpdate.Description = "Update smarthost"
	domainSMDelete = flaggy.NewSubcommand("delete")
	domainSMDelete.Description = "Delete smarthost"

	ldap = flaggy.NewSubcommand("ldap")
	ldap.Description = "AD/LDAP settings management"
	ldapGet = flaggy.NewSubcommand("show")
	ldapGet.Description = "Show AD/LDAP settings"
	ldapCreate = flaggy.NewSubcommand("create")
	ldapCreate.Description = "Create AD/LDAP settings"
	ldapUpdate = flaggy.NewSubcommand("update")
	ldapUpdate.Description = "Update AD/LDAP settings"
	ldapDelete = flaggy.NewSubcommand("delete")
	ldapDelete.Description = "Delete AD/LDAP settings"

	radius = flaggy.NewSubcommand("radius")
	radius.Description = "RADIUS settings management"
	radiusGet = flaggy.NewSubcommand("show")
	radiusGet.Description = "Show RADIUS settings"
	radiusCreate = flaggy.NewSubcommand("create")
	radiusCreate.Description = "Create RADIUS settings"
	radiusUpdate = flaggy.NewSubcommand("update")
	radiusUpdate.Description = "Update RADIUS settings"
	radiusDelete = flaggy.NewSubcommand("delete")
	radiusDelete.Description = "Delete RADIUS settings"

	organization = flaggy.NewSubcommand("organization")
	organization.Description = "Organization management"
	organizationGet = flaggy.NewSubcommand("show")
	organizationGet.Description = "Show organization details"
	organizationCreate = flaggy.NewSubcommand("create")
	organizationCreate.Description = "Create organization"
	organizationUpdate = flaggy.NewSubcommand("update")
	organizationUpdate.Description = "Update organization"
	organizationDelete = flaggy.NewSubcommand("delete")
	organizationDelete.Description = "Delete organization"

	relay = flaggy.NewSubcommand("relay")
	relay.Description = "Relay management"
	relayGet = flaggy.NewSubcommand("show")
	relayGet.Description = "Show relay details"
	relayCreate = flaggy.NewSubcommand("create")
	relayCreate.Description = "Create relay"
	relayUpdate = flaggy.NewSubcommand("update")
	relayUpdate.Description = "Update relay"
	relayDelete = flaggy.NewSubcommand("delete")
	relayDelete.Description = "Delete relay"

	fallbackServers = flaggy.NewSubcommand("fallbackservers")
	fallbackServers.Description = "List Fallback Servers"

	fallbackServer = flaggy.NewSubcommand("fallbackserver")
	fallbackServer.Description = "Fallback Server management"
	fallbackServerGet = flaggy.NewSubcommand("show")
	fallbackServerGet.Description = "Show fallback server details"
	fallbackServerCreate = flaggy.NewSubcommand("create")
	fallbackServerCreate.Description = "Create fallback server"
	fallbackServerUpdate = flaggy.NewSubcommand("update")
	fallbackServerUpdate.Description = "Update fallback server"
	fallbackServerDelete = flaggy.NewSubcommand("delete")
	fallbackServerDelete.Description = "Delete fallback server"

	organizationSMs = flaggy.NewSubcommand("smarthosts")
	organizationSMs.Description = "List smarthosts"

	organizationSM = flaggy.NewSubcommand("smarthost")
	organizationSM.Description = "Smarthost management"
	organizationSMGet = flaggy.NewSubcommand("show")
	organizationSMGet.Description = "Show smarthost details"
	organizationSMCreate = flaggy.NewSubcommand("create")
	organizationSMCreate.Description = "Create smarthost"
	organizationSMUpdate = flaggy.NewSubcommand("update")
	organizationSMUpdate.Description = "Update smarthost"
	organizationSMDelete = flaggy.NewSubcommand("delete")
	organizationSMDelete.Description = "Delete smarthost"

	organizations = flaggy.NewSubcommand("organizations")
	organizations.Description = "List Organizations"

	system = flaggy.NewSubcommand("system")
	system.Description = "System Status"

	user.AttachSubcommand(userGet, 1)
	user.AttachSubcommand(userCreate, 1)
	user.AttachSubcommand(userUpdate, 1)
	user.AttachSubcommand(userDelete, 1)
	user.AttachSubcommand(userAlias, 1)
	userAlias.AttachSubcommand(userAliasGet, 1)
	userAlias.AttachSubcommand(userAliasCreate, 1)
	userAlias.AttachSubcommand(userAliasUpdate, 1)
	userAlias.AttachSubcommand(userAliasDelete, 1)
	flaggy.AttachSubcommand(user, 1)
	flaggy.AttachSubcommand(users, 1)
	domain.AttachSubcommand(domainGet, 1)
	domain.AttachSubcommand(domainCreate, 1)
	domain.AttachSubcommand(domainUpdate, 1)
	domain.AttachSubcommand(domainDelete, 1)
	domain.AttachSubcommand(domainAliases, 1)
	domain.AttachSubcommand(domainAlias, 1)
	domainAlias.AttachSubcommand(domainAliasGet, 1)
	domainAlias.AttachSubcommand(domainAliasCreate, 1)
	domainAlias.AttachSubcommand(domainAliasUpdate, 1)
	domainAlias.AttachSubcommand(domainAliasDelete, 1)
	domain.AttachSubcommand(domainDSs, 1)
	domain.AttachSubcommand(domainDS, 1)
	domain.AttachSubcommand(userDSs, 1)
	domain.AttachSubcommand(userDS, 1)
	domain.AttachSubcommand(domainASs, 1)
	domain.AttachSubcommand(domainAS, 1)
	domain.AttachSubcommand(domainSMs, 1)
	domain.AttachSubcommand(domainSM, 1)
	domainDS.AttachSubcommand(domainDSGet, 1)
	domainDS.AttachSubcommand(domainDSCreate, 1)
	domainDS.AttachSubcommand(domainDSUpdate, 1)
	domainDS.AttachSubcommand(domainDSDelete, 1)
	userDS.AttachSubcommand(userDSGet, 1)
	userDS.AttachSubcommand(userDSCreate, 1)
	userDS.AttachSubcommand(userDSUpdate, 1)
	userDS.AttachSubcommand(userDSDelete, 1)
	domainAS.AttachSubcommand(domainASGet, 1)
	domainAS.AttachSubcommand(domainASCreate, 1)
	domainAS.AttachSubcommand(domainASUpdate, 1)
	domainAS.AttachSubcommand(domainASDelete, 1)
	domainAS.AttachSubcommand(ldap, 1)
	domainAS.AttachSubcommand(radius, 1)
	domainSM.AttachSubcommand(domainSMGet, 1)
	domainSM.AttachSubcommand(domainSMCreate, 1)
	domainSM.AttachSubcommand(domainSMUpdate, 1)
	domainSM.AttachSubcommand(domainSMDelete, 1)
	ldap.AttachSubcommand(ldapGet, 1)
	ldap.AttachSubcommand(ldapCreate, 1)
	ldap.AttachSubcommand(ldapUpdate, 1)
	ldap.AttachSubcommand(ldapDelete, 1)
	radius.AttachSubcommand(radiusGet, 1)
	radius.AttachSubcommand(radiusCreate, 1)
	radius.AttachSubcommand(radiusUpdate, 1)
	radius.AttachSubcommand(radiusDelete, 1)
	flaggy.AttachSubcommand(domain, 1)
	flaggy.AttachSubcommand(domains, 1)
	flaggy.AttachSubcommand(organization, 1)
	organization.AttachSubcommand(organizationGet, 1)
	organization.AttachSubcommand(organizationCreate, 1)
	organization.AttachSubcommand(organizationUpdate, 1)
	organization.AttachSubcommand(organizationDelete, 1)
	organization.AttachSubcommand(relay, 1)
	organization.AttachSubcommand(fallbackServers, 1)
	organization.AttachSubcommand(fallbackServer, 1)
	organization.AttachSubcommand(organizationSMs, 1)
	organization.AttachSubcommand(organizationSM, 1)
	relay.AttachSubcommand(relayGet, 1)
	relay.AttachSubcommand(relayCreate, 1)
	relay.AttachSubcommand(relayUpdate, 1)
	relay.AttachSubcommand(relayDelete, 1)
	fallbackServer.AttachSubcommand(fallbackServerGet, 1)
	fallbackServer.AttachSubcommand(fallbackServerCreate, 1)
	fallbackServer.AttachSubcommand(fallbackServerUpdate, 1)
	fallbackServer.AttachSubcommand(fallbackServerDelete, 1)
	organizationSM.AttachSubcommand(organizationSMGet, 1)
	organizationSM.AttachSubcommand(organizationSMCreate, 1)
	organizationSM.AttachSubcommand(organizationSMUpdate, 1)
	organizationSM.AttachSubcommand(organizationSMDelete, 1)
	flaggy.AttachSubcommand(organizations, 1)
	flaggy.AttachSubcommand(system, 1)
	flaggy.String(&serverURL, "s", "server-url", "Baruwa server url")
	flaggy.String(&apiToken, "k", "api-token", "Baruwa API OAUTH Token")
	flaggy.Parse()
}
<commit_msg>FIX: Remove kingpin<commit_after><|endoftext|>


<commit_before>package backend

import (
	"fmt"
	"os"
	"time"

	gw "github.com/cvmfs/gateway/internal/gateway"
	"github.com/pkg/errors"
	bolt "go.etcd.io/bbolt"
)

// EmbeddedLeaseDB is a LeaseDB backed by BoltDB
type EmbeddedLeaseDB struct {
	store *bolt.DB
}

// NewEmbeddedLeaseDB creates a new embedded lease DB
func NewEmbeddedLeaseDB(workDir string) (*EmbeddedLeaseDB, error) {
	if err := os.MkdirAll(workDir, 0777); err != nil {
		return nil, errors.Wrap(err, "could not create directory for backing store")
	}
	store, err := bolt.Open(workDir+"/lease.db", 0666, nil)
	if err != nil {
		return nil, errors.Wrap(err, "could not open backing store (BoltDB)")
	}

	gw.Log.Info().
		Str("component", "leasedb").
		Msgf("database opened (work dir: %v)", workDir)

	return &EmbeddedLeaseDB{store}, nil
}

// Close the lease database
func (db *EmbeddedLeaseDB) Close() error {
	return db.store.Close()
}

// NewLease attemps to acquire a new lease for the given path
func (db *EmbeddedLeaseDB) NewLease(keyID, leasePath string, token LeaseToken) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}

		lease := Lease{KeyID: keyID, Token: token}
		buf, err := lease.Serialize()
		if err != nil {
			return err
		}

		tokenBucket, err := txn.CreateBucketIfNotExists([]byte("tokens"))
		if err != nil {
			return errors.Wrap(err, "could not create bucket: 'tokens'")
		}

		repoBucket, err := txn.CreateBucketIfNotExists([]byte(repoName))
		if err != nil {
			return errors.Wrap(err, fmt.Sprintf("could not create bucket: '%v'", repoName))
		}

		// Iterate through the key of the bucket corresponding to the repository
		// and find any conflicting lease (there can be at most 1)
		var existing struct {
			path  string
			lease *Lease
		}

		cursor := repoBucket.Cursor()
		for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
			kPath := string(k)
			if CheckPathOverlap(kPath, subPath) {
				l, err := DeserializeLease(v)
				if err != nil {
					return err
				}
				existing.lease = l
				existing.path = kPath
				break
			}
		}

		// If a conflicting lease exists, examine its expiration time
		if existing.path != "" {
			timeLeft := existing.lease.Token.Expiration.Sub(time.Now())
			if timeLeft > 0 {
				gw.Log.Debug().
					Str("component", "leasedb").
					Msgf("new lease request failed: path_busy, time left: %v s", timeLeft.Seconds())
				return PathBusyError{timeLeft}
			}

			tokenBucket.Delete([]byte(existing.lease.Token.TokenStr))
			repoBucket.Delete([]byte(existing.path))
			tokenBucket.Put([]byte(token.TokenStr), []byte(leasePath))
			repoBucket.Put([]byte(subPath), buf)
		} else {
			tokenBucket.Put([]byte(token.TokenStr), []byte(leasePath))
			repoBucket.Put([]byte(subPath), buf)
		}

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("new lease request successful")

		return nil
	})
}

// GetLeases returns a list of all active leases
func (db *EmbeddedLeaseDB) GetLeases() (map[string]Lease, error) {
	leases := make(map[string]Lease)
	err := db.store.View(func(txn *bolt.Tx) error {
		if err := txn.ForEach(func(name []byte, b *bolt.Bucket) error {
			bucketName := string(name)
			if bucketName == "tokens" {
				return nil
			}
			if err := b.ForEach(func(k, v []byte) error {
				leasePath := bucketName + string(k)
				lease, err := DeserializeLease(v)
				if err != nil {
					return err
				}
				leases[leasePath] = *lease
				return nil
			}); err != nil {
				return errors.Wrap(
					err, fmt.Sprintf("iteration error in bucket: %v", bucketName))
			}
			return nil
		}); err != nil {
			return errors.Wrap(err, "iteration error over repository buckets")
		}

		return nil
	})
	return leases, err
}

// GetLeaseForPath returns the lease for a given path
func (db *EmbeddedLeaseDB) GetLeaseForPath(leasePath string) (*Lease, error) {
	lease := Lease{}
	err := db.store.View(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}
		v := bucket.Get([]byte(subPath))
		if v == nil {
			return InvalidLeaseError{}
		}
		l, err := DeserializeLease(v)
		if err != nil {
			return err
		}
		lease = *l
		return nil
	})
	return &lease, err
}

// GetLeaseForToken returns the lease for a given token string
func (db *EmbeddedLeaseDB) GetLeaseForToken(tokenStr string) (string, *Lease, error) {
	lease := Lease{}
	var leasePath string
	err := db.store.View(func(txn *bolt.Tx) error {
		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		lPath := tokens.Get([]byte(tokenStr))
		if lPath == nil {
			return InvalidLeaseError{}
		}

		repoName, subPath, err := SplitLeasePath(string(lPath))
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}
		v := bucket.Get([]byte(subPath))
		if v == nil {
			return InvalidLeaseError{}
		}
		l, err := DeserializeLease(v)
		if err != nil {
			return err
		}
		leasePath = string(lPath)
		lease = *l
		return nil
	})
	return leasePath, &lease, err
}

// CancelLeases cancels all active leases
func (db *EmbeddedLeaseDB) CancelLeases() error {
	return db.store.Update(func(txn *bolt.Tx) error {
		txn.ForEach(func(name []byte, b *bolt.Bucket) error {
			txn.DeleteBucket(name)
			return nil
		})

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("all leases cancelled")

		return nil
	})
}

// CancelLeaseForPath cancels the leases for a given path
func (db *EmbeddedLeaseDB) CancelLeaseForPath(leasePath string) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}

		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}

		v := bucket.Get([]byte(subPath))
		if v == nil {
			gw.Log.Debug().
				Str("component", "leasedb").
				Msgf("cancellation failed, invalid lease path: %v", leasePath)
			return InvalidLeaseError{}
		}
		lease, err := DeserializeLease(v)
		if err != nil {
			return err
		}

		bucket.Delete([]byte(subPath))
		tokens.Delete([]byte(lease.Token.TokenStr))

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("lease cancelled for path: %v", leasePath)

		return nil
	})
}

// CancelLeaseForToken cancels the lease for a token string
func (db *EmbeddedLeaseDB) CancelLeaseForToken(tokenStr string) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		leasePath := tokens.Get([]byte(tokenStr))
		if leasePath == nil {
			gw.Log.Debug().
				Str("component", "leasedb").
				Msgf("cancellation failed, invalid token: %v", tokenStr)
			return InvalidLeaseError{}
		}

		repoName, subPath, err := SplitLeasePath(string(leasePath))
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}

		bucket.Delete([]byte(subPath))
		tokens.Delete([]byte(tokenStr))

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("lease cancelled for path: %v, token: %v",
				string(leasePath), tokenStr)

		return nil
	})
}
<commit_msg>More information in logging in leasedb_embedded<commit_after>package backend

import (
	"fmt"
	"os"
	"time"

	gw "github.com/cvmfs/gateway/internal/gateway"
	"github.com/pkg/errors"
	bolt "go.etcd.io/bbolt"
)

// EmbeddedLeaseDB is a LeaseDB backed by BoltDB
type EmbeddedLeaseDB struct {
	store *bolt.DB
}

// NewEmbeddedLeaseDB creates a new embedded lease DB
func NewEmbeddedLeaseDB(workDir string) (*EmbeddedLeaseDB, error) {
	if err := os.MkdirAll(workDir, 0777); err != nil {
		return nil, errors.Wrap(err, "could not create directory for backing store")
	}
	store, err := bolt.Open(workDir+"/lease.db", 0666, nil)
	if err != nil {
		return nil, errors.Wrap(err, "could not open backing store (BoltDB)")
	}

	gw.Log.Info().
		Str("component", "leasedb").
		Msgf("database opened (work dir: %v)", workDir)

	return &EmbeddedLeaseDB{store}, nil
}

// Close the lease database
func (db *EmbeddedLeaseDB) Close() error {
	return db.store.Close()
}

// NewLease attemps to acquire a new lease for the given path
func (db *EmbeddedLeaseDB) NewLease(keyID, leasePath string, token LeaseToken) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}

		lease := Lease{KeyID: keyID, Token: token}
		buf, err := lease.Serialize()
		if err != nil {
			return err
		}

		tokenBucket, err := txn.CreateBucketIfNotExists([]byte("tokens"))
		if err != nil {
			return errors.Wrap(err, "could not create bucket: 'tokens'")
		}

		repoBucket, err := txn.CreateBucketIfNotExists([]byte(repoName))
		if err != nil {
			return errors.Wrap(err, fmt.Sprintf("could not create bucket: '%v'", repoName))
		}

		// Iterate through the key of the bucket corresponding to the repository
		// and find any conflicting lease (there can be at most 1)
		var existing struct {
			path  string
			lease *Lease
		}

		cursor := repoBucket.Cursor()
		for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
			kPath := string(k)
			if CheckPathOverlap(kPath, subPath) {
				l, err := DeserializeLease(v)
				if err != nil {
					return err
				}
				existing.lease = l
				existing.path = kPath
				break
			}
		}

		// If a conflicting lease exists, examine its expiration time
		if existing.path != "" {
			timeLeft := existing.lease.Token.Expiration.Sub(time.Now())
			if timeLeft > 0 {
				gw.Log.Debug().
					Str("component", "leasedb").
					Msgf("new lease request failed: path_busy, time left: %v s", timeLeft.Seconds())
				return PathBusyError{timeLeft}
			}

			tokenBucket.Delete([]byte(existing.lease.Token.TokenStr))
			repoBucket.Delete([]byte(existing.path))
			tokenBucket.Put([]byte(token.TokenStr), []byte(leasePath))
			repoBucket.Put([]byte(subPath), buf)
		} else {
			tokenBucket.Put([]byte(token.TokenStr), []byte(leasePath))
			repoBucket.Put([]byte(subPath), buf)
		}

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("lease granted with key: %v, path: %v", keyID, leasePath)

		return nil
	})
}

// GetLeases returns a list of all active leases
func (db *EmbeddedLeaseDB) GetLeases() (map[string]Lease, error) {
	leases := make(map[string]Lease)
	err := db.store.View(func(txn *bolt.Tx) error {
		if err := txn.ForEach(func(name []byte, b *bolt.Bucket) error {
			bucketName := string(name)
			if bucketName == "tokens" {
				return nil
			}
			if err := b.ForEach(func(k, v []byte) error {
				leasePath := bucketName + string(k)
				lease, err := DeserializeLease(v)
				if err != nil {
					return err
				}
				leases[leasePath] = *lease
				return nil
			}); err != nil {
				return errors.Wrap(
					err, fmt.Sprintf("iteration error in bucket: %v", bucketName))
			}
			return nil
		}); err != nil {
			return errors.Wrap(err, "iteration error over repository buckets")
		}

		return nil
	})
	return leases, err
}

// GetLeaseForPath returns the lease for a given path
func (db *EmbeddedLeaseDB) GetLeaseForPath(leasePath string) (*Lease, error) {
	lease := Lease{}
	err := db.store.View(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}
		v := bucket.Get([]byte(subPath))
		if v == nil {
			return InvalidLeaseError{}
		}
		l, err := DeserializeLease(v)
		if err != nil {
			return err
		}
		lease = *l
		return nil
	})
	return &lease, err
}

// GetLeaseForToken returns the lease for a given token string
func (db *EmbeddedLeaseDB) GetLeaseForToken(tokenStr string) (string, *Lease, error) {
	lease := Lease{}
	var leasePath string
	err := db.store.View(func(txn *bolt.Tx) error {
		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		lPath := tokens.Get([]byte(tokenStr))
		if lPath == nil {
			return InvalidLeaseError{}
		}

		repoName, subPath, err := SplitLeasePath(string(lPath))
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}
		v := bucket.Get([]byte(subPath))
		if v == nil {
			return InvalidLeaseError{}
		}
		l, err := DeserializeLease(v)
		if err != nil {
			return err
		}
		leasePath = string(lPath)
		lease = *l
		return nil
	})
	return leasePath, &lease, err
}

// CancelLeases cancels all active leases
func (db *EmbeddedLeaseDB) CancelLeases() error {
	return db.store.Update(func(txn *bolt.Tx) error {
		txn.ForEach(func(name []byte, b *bolt.Bucket) error {
			txn.DeleteBucket(name)
			return nil
		})

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("all leases cancelled")

		return nil
	})
}

// CancelLeaseForPath cancels the leases for a given path
func (db *EmbeddedLeaseDB) CancelLeaseForPath(leasePath string) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		repoName, subPath, err := SplitLeasePath(leasePath)
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}

		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}

		v := bucket.Get([]byte(subPath))
		if v == nil {
			gw.Log.Debug().
				Str("component", "leasedb").
				Msgf("cancellation failed, invalid lease path: %v", leasePath)
			return InvalidLeaseError{}
		}
		lease, err := DeserializeLease(v)
		if err != nil {
			return err
		}

		bucket.Delete([]byte(subPath))
		tokens.Delete([]byte(lease.Token.TokenStr))

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("lease cancelled for path: %v", leasePath)

		return nil
	})
}

// CancelLeaseForToken cancels the lease for a token string
func (db *EmbeddedLeaseDB) CancelLeaseForToken(tokenStr string) error {
	return db.store.Update(func(txn *bolt.Tx) error {
		tokens := txn.Bucket([]byte("tokens"))
		if tokens == nil {
			return fmt.Errorf("missing 'tokens' bucket")
		}
		leasePath := tokens.Get([]byte(tokenStr))
		if leasePath == nil {
			gw.Log.Debug().
				Str("component", "leasedb").
				Msgf("cancellation failed, invalid token: %v", tokenStr)
			return InvalidLeaseError{}
		}

		repoName, subPath, err := SplitLeasePath(string(leasePath))
		if err != nil {
			return errors.Wrap(err, "invalid lease path")
		}
		bucket := txn.Bucket([]byte(repoName))
		if bucket == nil {
			return fmt.Errorf("invalid repo name: %v", repoName)
		}

		bucket.Delete([]byte(subPath))
		tokens.Delete([]byte(tokenStr))

		gw.Log.Debug().
			Str("component", "leasedb").
			Msgf("lease cancelled for path: %v", string(leasePath))

		return nil
	})
}
<|endoftext|>


<commit_before>package ipcc

import (
	"encoding/binary"
	"net"
	"sort"
)

//go:generate go run gen.go

func lookup4(ip4 net.IP) string {
	ip := binary.BigEndian.Uint32(ip4)
	i := sort.Search(len(ipv4blocks), func(n int) bool {
		return ipv4blocks[n].e >= ip
	})
	if i < len(ipv4blocks) && ipv4blocks[i].s <= ip && ip <= ipv4blocks[i].e {
		return ccs[ipv4blocks[i].cc&0xff]
	}
	return ""
}

func lookup6(ip net.IP) string {
	prefix := binary.BigEndian.Uint64(ip)
	i := sort.Search(len(ipv6blocks), func(n int) bool {
		v := ipv6blocks[n]
		e := v.p + ^uint64(0)>>(v.l)
		return e >= prefix
	})
	if i < len(ipv6blocks) {
		v := ipv6blocks[i]
		e := v.p + ^uint64(0)>>(v.l)
		if v.p <= prefix && prefix <= e {
			return ccs[v.cc&0xff]
		}
	}
	return ""
}

func Lookup(ip net.IP) string {
	if ip4 := ip.To4(); ip4 != nil {
		return lookup4(ip4)
	}
	return lookup6(ip)
}
<commit_msg>package doc<commit_after>// Package ipcc provides IP to country code mapping
package ipcc

import (
	"encoding/binary"
	"net"
	"sort"
)

//go:generate go run gen.go

func lookup4(ip4 net.IP) string {
	ip := binary.BigEndian.Uint32(ip4)
	i := sort.Search(len(ipv4blocks), func(n int) bool {
		return ipv4blocks[n].e >= ip
	})
	if i < len(ipv4blocks) && ipv4blocks[i].s <= ip && ip <= ipv4blocks[i].e {
		return ccs[ipv4blocks[i].cc&0xff]
	}
	return ""
}

func lookup6(ip net.IP) string {
	prefix := binary.BigEndian.Uint64(ip)
	i := sort.Search(len(ipv6blocks), func(n int) bool {
		v := ipv6blocks[n]
		e := v.p + ^uint64(0)>>(v.l)
		return e >= prefix
	})
	if i < len(ipv6blocks) {
		v := ipv6blocks[i]
		e := v.p + ^uint64(0)>>(v.l)
		if v.p <= prefix && prefix <= e {
			return ccs[v.cc&0xff]
		}
	}
	return ""
}

// Lookup returns a 2 letter country code for the given IP or "" if the IP
// isn't found in the database.
func Lookup(ip net.IP) string {
	if ip4 := ip.To4(); ip4 != nil {
		return lookup4(ip4)
	}
	return lookup6(ip)
}
<|endoftext|>