<commit_before>// Copyright 2017 The clang-server 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 symbol

import (
	"net"

	flatbuffers "github.com/google/flatbuffers/go"
	"github.com/zchee/clang-server/indexdb"
	"github.com/zchee/clang-server/internal/log"
	"github.com/zchee/clang-server/internal/pathutil"
	"github.com/zchee/clang-server/symbol/internal/symbol"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

const port = ":50051"

func NewClangClient(cc *grpc.ClientConn) symbol.ClangClient {
	return symbol.NewClangClient(cc)
}

type server struct {
	db *indexdb.IndexDB
}

func (s *server) Completion(ctx context.Context, loc *symbol.Location) (*flatbuffers.Builder, error) {
	f := string(loc.FileName())
	dir, _ := pathutil.FindProjectRoot(f)
	db, err := indexdb.NewIndexDB(dir)
	if err != nil {
		return nil, err
	}
	s.db = db
	defer db.Close()

	buf, err := db.Get(f)
	if err != nil {
		return nil, err
	}

	file := GetRootAsFile(buf, 0)

	return file.Serialize(), nil
}

func Serve() {
	println("Serve")
	l, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatal(err)
	}

	s := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
	symbol.RegisterClangServer(s, &server{})
	if err := s.Serve(l); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>symbol/rpc: add godoc comment<commit_after>// Copyright 2017 The clang-server 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 symbol

import (
	"net"

	flatbuffers "github.com/google/flatbuffers/go"
	"github.com/zchee/clang-server/indexdb"
	"github.com/zchee/clang-server/internal/log"
	"github.com/zchee/clang-server/internal/pathutil"
	"github.com/zchee/clang-server/symbol/internal/symbol"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

const port = ":50051"

// NewClangClient retern the new symbol.ClangClient.
func NewClangClient(cc *grpc.ClientConn) symbol.ClangClient {
	return symbol.NewClangClient(cc)
}

type server struct {
	db *indexdb.IndexDB
}

func (s *server) Completion(ctx context.Context, loc *symbol.Location) (*flatbuffers.Builder, error) {
	f := string(loc.FileName())
	dir, _ := pathutil.FindProjectRoot(f)
	db, err := indexdb.NewIndexDB(dir)
	if err != nil {
		return nil, err
	}
	s.db = db
	defer db.Close()

	buf, err := db.Get(f)
	if err != nil {
		return nil, err
	}

	file := GetRootAsFile(buf, 0)

	return file.Serialize(), nil
}

// Serve serve clang-server server with the flatbuffers gRPC custom codec.
func Serve() {
	println("Serve")
	l, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatal(err)
	}

	s := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
	symbol.RegisterClangServer(s, &server{})
	if err := s.Serve(l); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


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

package integration

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"time"

	"gopkg.in/check.v1"
)

var (
	T            = NewCommand("tsuru").WithArgs
	allPlatforms = []string{
		"tsuru/python",
		"tsuru/go",
		"tsuru/buildpack",
		"tsuru/cordova",
		"tsuru/elixir",
		"tsuru/java",
		"tsuru/nodejs",
		"tsuru/php",
		"tsuru/play",
		"tsuru/pypy",
		"tsuru/python3",
		"tsuru/ruby",
		"tsuru/static",
	}
	allProvisioners = []string{
		"docker",
		"swarm",
	}
	flows = []ExecFlow{
		platformsToInstall(),
		installerConfigTest(),
		installerTest(),
		targetTest(),
		loginTest(),
		removeInstallNodes(),
		quotaTest(),
		teamTest(),
		poolAdd(),
		nodeRemove(),
		platformAdd(),
		exampleApps(),
	}
)

var installerConfig = `driver:
  name: virtualbox
  options:
    virtualbox-cpu-count: 2
    virtualbox-memory: 2048
hosts:
  apps:
    size: 2
components:
  tsuru:
    version: latest
    install-dashboard: false
`

func platformsToInstall() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platformimages"},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		for _, platImg := range allPlatforms {
			res.Env.Add("platformimages", platImg)
		}
	})
	return flow
}

func installerConfigTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"installerconfig"},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		f, err := ioutil.TempFile("", "installer-config")
		c.Assert(err, check.IsNil)
		defer f.Close()
		f.Write([]byte(installerConfig))
		res.Env.Set("installerconfig", f.Name())
	})
	flow.AddRollback(NewCommand("rm", "{{.installerconfig}}"))
	return flow
}

func installerTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"targetaddr"},
	}
	flow.Add(T("install", "--config", "{{.installerconfig}}").WithTimeout(9 * time.Minute))
	flow.AddRollback(T("uninstall", "-y"))
	flow.AddHook(func(c *check.C, res *Result) {
		regex := regexp.MustCompile(`(?si).*Core Hosts:.*?([\d.]+)\s.*`)
		parts := regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetHost := parts[1]
		regex = regexp.MustCompile(`(?si).*Tsuru API.*?\|\s(\d+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetPort := parts[1]
		res.Env.Set("targetaddr", fmt.Sprintf("http://%s:%s", targetHost, targetPort))
		regex = regexp.MustCompile(`\| (https?[^\s]+?) \|`)
		allParts := regex.FindAllStringSubmatch(res.Stdout.String(), -1)
		for _, parts = range allParts {
			c.Assert(parts, check.HasLen, 2)
			res.Env.Add("nodeopts", fmt.Sprintf("--register address=%s --cacert ~/.tsuru/installs/tsuru/certs/ca.pem --clientcert ~/.tsuru/installs/tsuru/certs/cert.pem --clientkey ~/.tsuru/installs/tsuru/certs/key.pem", parts[1]))
			res.Env.Add("nodestoremove", parts[1])
		}
		regex = regexp.MustCompile(`Username: (.+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		res.Env.Set("adminuser", parts[1])
		regex = regexp.MustCompile(`Password: (.+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		res.Env.Set("adminpassword", parts[1])
	})
	return flow
}

func targetTest() ExecFlow {
	flow := ExecFlow{}
	targetName := "integration-target"
	flow.Add(T("target-add", targetName, "{{.targetaddr}}"))
	flow.Add(T("target-list"), Expected{Stdout: `\s+` + targetName + ` .*`})
	flow.Add(T("target-set", targetName))
	return flow
}

func loginTest() ExecFlow {
	flow := ExecFlow{}
	flow.Add(T("login", "{{.adminuser}}").WithInput("{{.adminpassword}}"))
	return flow
}

func removeInstallNodes() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodestoremove",
		},
	}
	flow.Add(T("node-remove", "-y", "--no-rebalance", "{{.node}}"))
	return flow
}

func quotaTest() ExecFlow {
	flow := ExecFlow{}
	flow.Add(T("user-quota-change", "{{.adminuser}}", "100"))
	flow.Add(T("user-quota-view", "{{.adminuser}}"), Expected{Stdout: `(?s)Apps usage.*/100`})
	return flow
}

func teamTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"team"},
	}
	teamName := "integration-team"
	flow.Add(T("team-create", teamName))
	flow.AddHook(func(c *check.C, res *Result) {
		res.Env.Set("team", teamName)
	})
	flow.AddRollback(T("team-remove", "-y", teamName))
	return flow
}

func poolAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"poolnames"},
	}
	for _, prov := range allProvisioners {
		poolName := "ipool-" + prov
		flow.Add(T("pool-add", "--provisioner", prov, poolName))
		flow.AddHook(func(c *check.C, res *Result) {
			res.Env.Add("poolnames", poolName)
		})
		flow.AddRollback(T("pool-remove", "-y", poolName))
		flow.Add(T("pool-teams-add", poolName, "{{.team}}"))
		flow.AddRollback(T("pool-teams-remove", poolName, "{{.team}}"))
		flow.Add(T("node-add", "{{.nodeopts}}", "pool="+poolName))
		flow.Add(T("event-list"))
		flow.AddHook(func(c *check.C, res *Result) {
			nodeopts := res.Env.All("nodeopts")
			res.Env.Set("nodeopts", append(nodeopts[1:], nodeopts[0])...)
			regex := regexp.MustCompile(`node.create.*?node:\s+(.*?)\s+`)
			parts := regex.FindStringSubmatch(res.Stdout.String())
			c.Assert(parts, check.HasLen, 2)
			res.Env.Add("nodeaddrs", parts[1])
			regex = regexp.MustCompile(parts[1] + `.*?ready`)
			ok := retry(time.Minute, func() bool {
				res = T("node-list").Run(res.Env)
				return regex.MatchString(res.Stdout.String())
			})
			c.Assert(ok, check.Equals, true, check.Commentf("node not ready after 1 minute: %v", res))
		})
	}
	return flow
}

func nodeRemove() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodeaddrs",
		},
	}
	flow.AddRollback(T("node-remove", "-y", "--no-rebalance", "{{.node}}"))
	return flow
}

func platformAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platforms"},
		matrix: map[string]string{
			"platimg": "platformimages",
		},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		img := res.Env.Get("platimg")
		res.Env.Set("platimgsuffix", img[strings.LastIndex(img, "/")+1:])
	})
	flow.Add(T("platform-add", "iplat-{{.platimgsuffix}}", "-i", "{{.platimg}}"))
	flow.AddHook(func(c *check.C, res *Result) {
		res.Env.Add("platforms", "iplat-"+res.Env.Get("platimgsuffix"))
	})
	flow.AddRollback(T("platform-remove", "-y", "iplat-{{.platimgsuffix}}"))
	flow.Add(T("platform-list"), Expected{Stdout: "(?s).*- iplat-{{.platimgsuffix}}.*"})
	return flow
}

func exampleApps() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"pool": "poolnames",
			"plat": "platforms",
		},
	}
	appName := "iapp-{{.plat}}-{{.pool}}"
	flow.Add(T("app-create", appName, "{{.plat}}", "-t", "{{.team}}", "-o", "{{.pool}}"))
	flow.AddRollback(T("app-remove", "-y", "-a", appName))
	flow.Add(T("app-info", "-a", appName))
	flow.AddHook(func(c *check.C, res *Result) {
		platRE := regexp.MustCompile(`(?s)Platform: (.*?)\n`)
		parts := platRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		res.Env.Set("language", strings.Replace(parts[1], "iplat-", "", -1))
	})
	flow.Add(T("app-deploy", "-a", appName, "{{.examplesdir}}/{{.language}}"))
	flow.Add(T("app-info", "-a", appName))
	flow.AddHook(func(c *check.C, res *Result) {
		addrRE := regexp.MustCompile(`(?s)Address: (.*?)\n`)
		parts := addrRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		res.Env.Set("appaddr", parts[1])
	})
	flow.AddHook(func(c *check.C, res *Result) {
		cmd := NewCommand("curl", "-sSf", "http://{{.appaddr}}")
		ok := retry(time.Minute, func() bool {
			res = cmd.Run(res.Env)
			return res.ExitCode == 0
		})
		c.Assert(ok, check.Equals, true, check.Commentf("invalid result: %v", res))
	})
	return flow
}

func (s *S) TestBase(c *check.C) {
	env := NewEnvironment()
	if !env.Has("enabled") {
		return
	}
	var executedFlows []*ExecFlow
	defer func() {
		for i := len(executedFlows) - 1; i >= 0; i-- {
			executedFlows[i].Rollback(c, env)
		}
	}()
	for i := range flows {
		f := &flows[i]
		if len(f.provides) > 0 {
			providesAll := true
			for _, envVar := range f.provides {
				if env.Get(envVar) == "" {
					providesAll = false
					break
				}
			}
			if providesAll {
				continue
			}
		}
		executedFlows = append(executedFlows, f)
		f.Run(c, env)
	}
}
<commit_msg>integration: fix regex to parse username and password<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"time"

	"gopkg.in/check.v1"
)

var (
	T            = NewCommand("tsuru").WithArgs
	allPlatforms = []string{
		"tsuru/python",
		"tsuru/go",
		"tsuru/buildpack",
		"tsuru/cordova",
		"tsuru/elixir",
		"tsuru/java",
		"tsuru/nodejs",
		"tsuru/php",
		"tsuru/play",
		"tsuru/pypy",
		"tsuru/python3",
		"tsuru/ruby",
		"tsuru/static",
	}
	allProvisioners = []string{
		"docker",
		"swarm",
	}
	flows = []ExecFlow{
		platformsToInstall(),
		installerConfigTest(),
		installerTest(),
		targetTest(),
		loginTest(),
		removeInstallNodes(),
		quotaTest(),
		teamTest(),
		poolAdd(),
		nodeRemove(),
		platformAdd(),
		exampleApps(),
	}
)

var installerConfig = `driver:
  name: virtualbox
  options:
    virtualbox-cpu-count: 2
    virtualbox-memory: 2048
hosts:
  apps:
    size: 2
components:
  tsuru:
    version: latest
    install-dashboard: false
`

func platformsToInstall() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platformimages"},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		for _, platImg := range allPlatforms {
			res.Env.Add("platformimages", platImg)
		}
	})
	return flow
}

func installerConfigTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"installerconfig"},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		f, err := ioutil.TempFile("", "installer-config")
		c.Assert(err, check.IsNil)
		defer f.Close()
		f.Write([]byte(installerConfig))
		res.Env.Set("installerconfig", f.Name())
	})
	flow.AddRollback(NewCommand("rm", "{{.installerconfig}}"))
	return flow
}

func installerTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"targetaddr"},
	}
	flow.Add(T("install", "--config", "{{.installerconfig}}").WithTimeout(9 * time.Minute))
	flow.AddRollback(T("uninstall", "-y"))
	flow.AddHook(func(c *check.C, res *Result) {
		regex := regexp.MustCompile(`(?si).*Core Hosts:.*?([\d.]+)\s.*`)
		parts := regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetHost := parts[1]
		regex = regexp.MustCompile(`(?si).*Tsuru API.*?\|\s(\d+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetPort := parts[1]
		res.Env.Set("targetaddr", fmt.Sprintf("http://%s:%s", targetHost, targetPort))
		regex = regexp.MustCompile(`\| (https?[^\s]+?) \|`)
		allParts := regex.FindAllStringSubmatch(res.Stdout.String(), -1)
		for _, parts = range allParts {
			c.Assert(parts, check.HasLen, 2)
			res.Env.Add("nodeopts", fmt.Sprintf("--register address=%s --cacert ~/.tsuru/installs/tsuru/certs/ca.pem --clientcert ~/.tsuru/installs/tsuru/certs/cert.pem --clientkey ~/.tsuru/installs/tsuru/certs/key.pem", parts[1]))
			res.Env.Add("nodestoremove", parts[1])
		}
		regex = regexp.MustCompile(`Username: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		res.Env.Set("adminuser", parts[1])
		regex = regexp.MustCompile(`Password: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		res.Env.Set("adminpassword", parts[1])
	})
	return flow
}

func targetTest() ExecFlow {
	flow := ExecFlow{}
	targetName := "integration-target"
	flow.Add(T("target-add", targetName, "{{.targetaddr}}"))
	flow.Add(T("target-list"), Expected{Stdout: `\s+` + targetName + ` .*`})
	flow.Add(T("target-set", targetName))
	return flow
}

func loginTest() ExecFlow {
	flow := ExecFlow{}
	flow.Add(T("login", "{{.adminuser}}").WithInput("{{.adminpassword}}"))
	return flow
}

func removeInstallNodes() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodestoremove",
		},
	}
	flow.Add(T("node-remove", "-y", "--no-rebalance", "{{.node}}"))
	return flow
}

func quotaTest() ExecFlow {
	flow := ExecFlow{}
	flow.Add(T("user-quota-change", "{{.adminuser}}", "100"))
	flow.Add(T("user-quota-view", "{{.adminuser}}"), Expected{Stdout: `(?s)Apps usage.*/100`})
	return flow
}

func teamTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"team"},
	}
	teamName := "integration-team"
	flow.Add(T("team-create", teamName))
	flow.AddHook(func(c *check.C, res *Result) {
		res.Env.Set("team", teamName)
	})
	flow.AddRollback(T("team-remove", "-y", teamName))
	return flow
}

func poolAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"poolnames"},
	}
	for _, prov := range allProvisioners {
		poolName := "ipool-" + prov
		flow.Add(T("pool-add", "--provisioner", prov, poolName))
		flow.AddHook(func(c *check.C, res *Result) {
			res.Env.Add("poolnames", poolName)
		})
		flow.AddRollback(T("pool-remove", "-y", poolName))
		flow.Add(T("pool-teams-add", poolName, "{{.team}}"))
		flow.AddRollback(T("pool-teams-remove", poolName, "{{.team}}"))
		flow.Add(T("node-add", "{{.nodeopts}}", "pool="+poolName))
		flow.Add(T("event-list"))
		flow.AddHook(func(c *check.C, res *Result) {
			nodeopts := res.Env.All("nodeopts")
			res.Env.Set("nodeopts", append(nodeopts[1:], nodeopts[0])...)
			regex := regexp.MustCompile(`node.create.*?node:\s+(.*?)\s+`)
			parts := regex.FindStringSubmatch(res.Stdout.String())
			c.Assert(parts, check.HasLen, 2)
			res.Env.Add("nodeaddrs", parts[1])
			regex = regexp.MustCompile(parts[1] + `.*?ready`)
			ok := retry(time.Minute, func() bool {
				res = T("node-list").Run(res.Env)
				return regex.MatchString(res.Stdout.String())
			})
			c.Assert(ok, check.Equals, true, check.Commentf("node not ready after 1 minute: %v", res))
		})
	}
	return flow
}

func nodeRemove() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodeaddrs",
		},
	}
	flow.AddRollback(T("node-remove", "-y", "--no-rebalance", "{{.node}}"))
	return flow
}

func platformAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platforms"},
		matrix: map[string]string{
			"platimg": "platformimages",
		},
	}
	flow.AddHook(func(c *check.C, res *Result) {
		img := res.Env.Get("platimg")
		res.Env.Set("platimgsuffix", img[strings.LastIndex(img, "/")+1:])
	})
	flow.Add(T("platform-add", "iplat-{{.platimgsuffix}}", "-i", "{{.platimg}}"))
	flow.AddHook(func(c *check.C, res *Result) {
		res.Env.Add("platforms", "iplat-"+res.Env.Get("platimgsuffix"))
	})
	flow.AddRollback(T("platform-remove", "-y", "iplat-{{.platimgsuffix}}"))
	flow.Add(T("platform-list"), Expected{Stdout: "(?s).*- iplat-{{.platimgsuffix}}.*"})
	return flow
}

func exampleApps() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"pool": "poolnames",
			"plat": "platforms",
		},
	}
	appName := "iapp-{{.plat}}-{{.pool}}"
	flow.Add(T("app-create", appName, "{{.plat}}", "-t", "{{.team}}", "-o", "{{.pool}}"))
	flow.AddRollback(T("app-remove", "-y", "-a", appName))
	flow.Add(T("app-info", "-a", appName))
	flow.AddHook(func(c *check.C, res *Result) {
		platRE := regexp.MustCompile(`(?s)Platform: (.*?)\n`)
		parts := platRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		res.Env.Set("language", strings.Replace(parts[1], "iplat-", "", -1))
	})
	flow.Add(T("app-deploy", "-a", appName, "{{.examplesdir}}/{{.language}}"))
	flow.Add(T("app-info", "-a", appName))
	flow.AddHook(func(c *check.C, res *Result) {
		addrRE := regexp.MustCompile(`(?s)Address: (.*?)\n`)
		parts := addrRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		res.Env.Set("appaddr", parts[1])
	})
	flow.AddHook(func(c *check.C, res *Result) {
		cmd := NewCommand("curl", "-sSf", "http://{{.appaddr}}")
		ok := retry(time.Minute, func() bool {
			res = cmd.Run(res.Env)
			return res.ExitCode == 0
		})
		c.Assert(ok, check.Equals, true, check.Commentf("invalid result: %v", res))
	})
	return flow
}

func (s *S) TestBase(c *check.C) {
	env := NewEnvironment()
	if !env.Has("enabled") {
		return
	}
	var executedFlows []*ExecFlow
	defer func() {
		for i := len(executedFlows) - 1; i >= 0; i-- {
			executedFlows[i].Rollback(c, env)
		}
	}()
	for i := range flows {
		f := &flows[i]
		if len(f.provides) > 0 {
			providesAll := true
			for _, envVar := range f.provides {
				if env.Get(envVar) == "" {
					providesAll = false
					break
				}
			}
			if providesAll {
				continue
			}
		}
		executedFlows = append(executedFlows, f)
		f.Run(c, env)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Ceph-CSI Authors.

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

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

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

package cephfs

import (
	"context"
	"strings"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/golang/protobuf/ptypes/timestamp"
	klog "k8s.io/klog/v2"
)

// cephfsSnapshot represents a CSI snapshot and its cluster information.
type cephfsSnapshot struct {
	NamePrefix string
	Monitors   string
	// MetadataPool & Pool fields are not used atm. But its definitely good to have it in this struct
	// so keeping it here
	MetadataPool string
	Pool         string
	ClusterID    string
	RequestName  string
}

func createSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"create",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to create subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func deleteSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"rm",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--force",
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to delete subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

type snapshotInfo struct {
	CreatedAt        string `json:"created_at"`
	CreationTime     *timestamp.Timestamp
	DataPool         string `json:"data_pool"`
	HasPendingClones string `json:"has_pending_clones"`
	Protected        string `json:"protected"`
	Size             int    `json:"size"`
}

func getSnapshotInfo(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) (snapshotInfo, error) {
	snap := snapshotInfo{}
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"info",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--format=json",
	}
	err := execCommandJSON(
		ctx,
		&snap,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapNotFound.Error()) {
			return snapshotInfo{}, err
		}
		util.ErrorLog(ctx, "failed to get subvolume snapshot info %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return snapshotInfo{}, err
	}
	return snap, nil
}

func protectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"protect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to protect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func unprotectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"unprotect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		// Incase the snap is already unprotected we get ErrSnapProtectionExist error code
		// in that case we are safe and we could discard this error.
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to unprotect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func cloneSnapshot(ctx context.Context, parentVolOptions *volumeOptions, cr *util.Credentials, volID, snapID, cloneID volumeID, cloneVolOptions *volumeOptions) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"clone",
		parentVolOptions.FsName,
		string(volID),
		string(snapID),
		string(cloneID),
		"--group_name",
		parentVolOptions.SubvolumeGroup,
		"--target_group_name",
		cloneVolOptions.SubvolumeGroup,
		"-m", parentVolOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}
	if cloneVolOptions.Pool != "" {
		args = append(args, "--pool_layout", cloneVolOptions.Pool)
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)

	if err != nil {
		klog.Errorf(util.Log(ctx, "failed to clone subvolume snapshot %s %s(%s) in fs %s"), string(cloneID), string(volID), err, parentVolOptions.FsName)
		if strings.HasPrefix(err.Error(), ErrVolumeNotFound.Error()) {
			return ErrVolumeNotFound
		}
		return err
	}
	return nil
}
<commit_msg>cephfs: replace Errorf with ErrorLog in cloneSnapshot<commit_after>/*
Copyright 2020 The Ceph-CSI Authors.

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

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

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

package cephfs

import (
	"context"
	"strings"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/golang/protobuf/ptypes/timestamp"
)

// cephfsSnapshot represents a CSI snapshot and its cluster information.
type cephfsSnapshot struct {
	NamePrefix string
	Monitors   string
	// MetadataPool & Pool fields are not used atm. But its definitely good to have it in this struct
	// so keeping it here
	MetadataPool string
	Pool         string
	ClusterID    string
	RequestName  string
}

func createSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"create",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to create subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func deleteSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"rm",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--force",
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to delete subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

type snapshotInfo struct {
	CreatedAt        string `json:"created_at"`
	CreationTime     *timestamp.Timestamp
	DataPool         string `json:"data_pool"`
	HasPendingClones string `json:"has_pending_clones"`
	Protected        string `json:"protected"`
	Size             int    `json:"size"`
}

func getSnapshotInfo(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) (snapshotInfo, error) {
	snap := snapshotInfo{}
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"info",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--format=json",
	}
	err := execCommandJSON(
		ctx,
		&snap,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapNotFound.Error()) {
			return snapshotInfo{}, err
		}
		util.ErrorLog(ctx, "failed to get subvolume snapshot info %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return snapshotInfo{}, err
	}
	return snap, nil
}

func protectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"protect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to protect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func unprotectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"unprotect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		// Incase the snap is already unprotected we get ErrSnapProtectionExist error code
		// in that case we are safe and we could discard this error.
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to unprotect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func cloneSnapshot(ctx context.Context, parentVolOptions *volumeOptions, cr *util.Credentials, volID, snapID, cloneID volumeID, cloneVolOptions *volumeOptions) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"clone",
		parentVolOptions.FsName,
		string(volID),
		string(snapID),
		string(cloneID),
		"--group_name",
		parentVolOptions.SubvolumeGroup,
		"--target_group_name",
		cloneVolOptions.SubvolumeGroup,
		"-m", parentVolOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}
	if cloneVolOptions.Pool != "" {
		args = append(args, "--pool_layout", cloneVolOptions.Pool)
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)

	if err != nil {
		util.ErrorLog(ctx, "failed to clone subvolume snapshot %s %s(%s) in fs %s", string(cloneID), string(volID), err, parentVolOptions.FsName)
		if strings.HasPrefix(err.Error(), ErrVolumeNotFound.Error()) {
			return ErrVolumeNotFound
		}
		return err
	}
	return nil
}
<|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 frontend

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"golang.org/x/discovery/internal/config"
	"golang.org/x/discovery/internal/dcensus"
	"golang.org/x/discovery/internal/middleware"
	"golang.org/x/discovery/internal/postgres"
)

// Server handles requests for the various frontend pages.
type Server struct {
	http.Handler

	db              *postgres.DB
	templateDir     string
	reloadTemplates bool
	errorPage       []byte

	mu        sync.RWMutex // Protects all fields below
	templates map[string]*template.Template
}

// NewServer creates a new Server for the given database and template directory.
// reloadTemplates should be used during development when it can be helpful to
// reload templates from disk each time a page is loaded.
func NewServer(db *postgres.DB, staticPath string, reloadTemplates bool) (*Server, error) {
	templateDir := filepath.Join(staticPath, "html")
	ts, err := parsePageTemplates(templateDir)
	if err != nil {
		return nil, fmt.Errorf("error parsing templates: %v", err)
	}

	s := &Server{
		db:              db,
		templateDir:     templateDir,
		reloadTemplates: reloadTemplates,
		templates:       ts,
	}
	errorPageBytes, err := s.renderErrorPage(http.StatusInternalServerError, nil)
	if err != nil {
		return nil, fmt.Errorf("s.renderErrorPage(http.StatusInternalServerError, nil): %v", err)
	}
	s.errorPage = errorPageBytes

	r := dcensus.NewRouter()
	r.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticPath))))
	r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, fmt.Sprintf("%s/img/favicon.ico", http.Dir(staticPath)))
	})
	r.Handle("/pkg/", http.HandlerFunc(s.handleDetails))
	r.HandleFunc("/search", s.handleSearch)
	r.HandleFunc("/advanced-search", s.handleStaticPage("advanced_search.tmpl", "Advanced Search - Go Discovery"))
	r.HandleFunc("/license-policy", s.handleStaticPage("license_policy.tmpl", "Licenses - Go Discovery"))
	r.HandleFunc("/copyright", s.handleStaticPage("copyright.tmpl", "Copyright - Go Discovery"))
	r.HandleFunc("/tos", s.handleStaticPage("tos.tmpl", "Terms of Service - Go Discovery"))
	r.HandleFunc("/", s.handleIndexPage)
	s.Handler = r

	return s, nil
}

// handleIndexPage handles requests to the index page.
func (s *Server) handleIndexPage(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		s.handleStaticPage("index.tmpl", "Go Discovery")(w, r)
		return
	}

	query := strings.TrimPrefix(r.URL.Path, "/")
	s.serveErrorPage(w, r, http.StatusNotFound, &errorPage{
		Message:          fmt.Sprintf("%d %s", http.StatusNotFound, http.StatusText(http.StatusNotFound)),
		SecondaryMessage: suggestedSearch(query),
	})
}

func suggestedSearch(userInput string) template.HTML {
	safe := template.HTMLEscapeString(userInput)
	return template.HTML(fmt.Sprintf(`To search for packages like %q, <a href="/search?q=%s">click here</a>.</p>`, safe, safe))
}

// handleStaticPage handles requests to a template that contains no dynamic
// content.
func (s *Server) handleStaticPage(templateName, title string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		s.servePage(w, templateName, basePage{Title: title})
	}
}

// basePage contains fields shared by all pages when rendering templates.
type basePage struct {
	Title string
	Query string
	Nonce string
}

// newBasePage returns a base page for the given request and title.
func newBasePage(r *http.Request, title string) basePage {
	nonce, ok := middleware.GetNonce(r.Context())
	if !ok {
		log.Printf("middleware.GetNonce: nonce was not set")
	}
	return basePage{
		Title: title,
		Query: searchQuery(r),
		Nonce: nonce,
	}
}

// GoogleAnalyticsTrackingID returns the tracking ID from
// func (b basePage) GoogleAnalyticsTrackingID() string {
	return "UA-141356704-1"
}

// AppVersionLabel uniquely identifies the currently running binary. It can be
// used for cache-busting query parameters.
func (b basePage) AppVersionLabel() string {
	return config.AppVersionLabel()
}

// errorPage contains fields for rendering a HTTP error page.
type errorPage struct {
	basePage
	Message          string
	SecondaryMessage template.HTML
}

func (s *Server) serveErrorPage(w http.ResponseWriter, r *http.Request, status int, page *errorPage) {
	if page == nil {
		page = &errorPage{
			basePage: newBasePage(r, ""),
		}
	}
	buf, err := s.renderErrorPage(status, page)
	if err != nil {
		log.Printf("s.renderErrorPage(w, %d, %v): %v", status, page, err)
		buf = s.errorPage
		status = http.StatusInternalServerError
	}

	w.WriteHeader(status)
	if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
		log.Printf("Error copying template %q buffer to ResponseWriter: %v", "error.tmpl", err)
	}
}

// renderErrorPage executes error.tmpl with the given errorPage
func (s *Server) renderErrorPage(status int, page *errorPage) ([]byte, error) {
	statusInfo := fmt.Sprintf("%d %s", status, http.StatusText(status))
	if page == nil {
		page = &errorPage{
			Message: statusInfo,
			basePage: basePage{
				Title: statusInfo,
			},
		}
	}
	if page.Message == "" {
		page.Message = statusInfo
	}
	if page.Title == "" {
		page.Title = statusInfo
	}
	return s.renderPage("error.tmpl", page)
}

// servePage is used to execute all templates for a *Server.
func (s *Server) servePage(w http.ResponseWriter, templateName string, page interface{}) {
	if s.reloadTemplates {
		s.mu.Lock()
		var err error
		s.templates, err = parsePageTemplates(s.templateDir)
		s.mu.Unlock()
		if err != nil {
			log.Printf("Error parsing templates: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	buf, err := s.renderPage(templateName, page)
	if err != nil {
		log.Printf("s.renderPage(%q, %v): %v", templateName, page, err)
		w.WriteHeader(http.StatusInternalServerError)
		buf = s.errorPage
	}
	if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
		log.Printf("Error copying template %q buffer to ResponseWriter: %v", templateName, err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// renderPage executes the given templateName with page.
func (s *Server) renderPage(templateName string, page interface{}) ([]byte, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	var buf bytes.Buffer
	if err := s.templates[templateName].Execute(&buf, page); err != nil {
		log.Printf("Error executing page template %q: %v", templateName, err)
		return nil, err

	}
	return buf.Bytes(), nil
}

// parsePageTemplates parses html templates contained in the given base
// directory in order to generate a map of Name->*template.Template.
//
// Separate templates are used so that certain contextual functions (e.g.
// templateName) can be bound independently for each page.
func parsePageTemplates(base string) (map[string]*template.Template, error) {
	htmlSets := [][]string{
		{"index.tmpl"},
		{"error.tmpl"},
		{"search.tmpl"},
		{"advanced_search.tmpl"},
		{"copyright.tmpl"},
		{"license_policy.tmpl"},
		{"tos.tmpl"},
		{"doc.tmpl", "details.tmpl"},
		{"importedby.tmpl", "details.tmpl"},
		{"imports.tmpl", "details.tmpl"},
		{"licenses.tmpl", "details.tmpl"},
		{"module.tmpl", "details.tmpl"},
		{"readme.tmpl", "details.tmpl"},
		{"versions.tmpl", "details.tmpl"},
	}

	templates := make(map[string]*template.Template)
	for _, set := range htmlSets {
		t, err := template.New("base.tmpl").Funcs(template.FuncMap{
			"add":     func(i, j int) int { return i + j },
			"curYear": func() int { return time.Now().Year() },
			"pluralize": func(i int, s string) string {
				if i == 1 {
					return s
				}
				return s + "s"
			},
		}).ParseFiles(filepath.Join(base, "base.tmpl"))
		if err != nil {
			return nil, fmt.Errorf("ParseFiles: %v", err)
		}
		helperGlob := filepath.Join(base, "helpers", "*.tmpl")
		if _, err := t.ParseGlob(helperGlob); err != nil {
			return nil, fmt.Errorf("ParseGlob(%q): %v", helperGlob, err)
		}

		var files []string
		for _, f := range set {
			files = append(files, filepath.Join(base, "pages", f))
		}
		if _, err := t.ParseFiles(files...); err != nil {
			return nil, fmt.Errorf("ParseFiles(%v): %v", files, err)
		}
		templates[set[0]] = t
	}
	return templates, nil
}
<commit_msg>internal/frontend: add nonce to handleStaticPage<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 frontend

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"golang.org/x/discovery/internal/config"
	"golang.org/x/discovery/internal/dcensus"
	"golang.org/x/discovery/internal/middleware"
	"golang.org/x/discovery/internal/postgres"
)

// Server handles requests for the various frontend pages.
type Server struct {
	http.Handler

	db              *postgres.DB
	templateDir     string
	reloadTemplates bool
	errorPage       []byte

	mu        sync.RWMutex // Protects all fields below
	templates map[string]*template.Template
}

// NewServer creates a new Server for the given database and template directory.
// reloadTemplates should be used during development when it can be helpful to
// reload templates from disk each time a page is loaded.
func NewServer(db *postgres.DB, staticPath string, reloadTemplates bool) (*Server, error) {
	templateDir := filepath.Join(staticPath, "html")
	ts, err := parsePageTemplates(templateDir)
	if err != nil {
		return nil, fmt.Errorf("error parsing templates: %v", err)
	}

	s := &Server{
		db:              db,
		templateDir:     templateDir,
		reloadTemplates: reloadTemplates,
		templates:       ts,
	}
	errorPageBytes, err := s.renderErrorPage(http.StatusInternalServerError, nil)
	if err != nil {
		return nil, fmt.Errorf("s.renderErrorPage(http.StatusInternalServerError, nil): %v", err)
	}
	s.errorPage = errorPageBytes

	r := dcensus.NewRouter()
	r.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticPath))))
	r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, fmt.Sprintf("%s/img/favicon.ico", http.Dir(staticPath)))
	})
	r.Handle("/pkg/", http.HandlerFunc(s.handleDetails))
	r.HandleFunc("/search", s.handleSearch)
	r.HandleFunc("/advanced-search", s.handleStaticPage("advanced_search.tmpl", "Advanced Search - Go Discovery"))
	r.HandleFunc("/license-policy", s.handleStaticPage("license_policy.tmpl", "Licenses - Go Discovery"))
	r.HandleFunc("/copyright", s.handleStaticPage("copyright.tmpl", "Copyright - Go Discovery"))
	r.HandleFunc("/tos", s.handleStaticPage("tos.tmpl", "Terms of Service - Go Discovery"))
	r.HandleFunc("/", s.handleIndexPage)
	s.Handler = r

	return s, nil
}

// handleIndexPage handles requests to the index page.
func (s *Server) handleIndexPage(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		s.handleStaticPage("index.tmpl", "Go Discovery")(w, r)
		return
	}

	query := strings.TrimPrefix(r.URL.Path, "/")
	s.serveErrorPage(w, r, http.StatusNotFound, &errorPage{
		Message:          fmt.Sprintf("%d %s", http.StatusNotFound, http.StatusText(http.StatusNotFound)),
		SecondaryMessage: suggestedSearch(query),
	})
}

func suggestedSearch(userInput string) template.HTML {
	safe := template.HTMLEscapeString(userInput)
	return template.HTML(fmt.Sprintf(`To search for packages like %q, <a href="/search?q=%s">click here</a>.</p>`, safe, safe))
}

// handleStaticPage handles requests to a template that contains no dynamic
// content.
func (s *Server) handleStaticPage(templateName, title string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		s.servePage(w, templateName, newBasePage(r, title))
	}
}

// basePage contains fields shared by all pages when rendering templates.
type basePage struct {
	Title string
	Query string
	Nonce string
}

// newBasePage returns a base page for the given request and title.
func newBasePage(r *http.Request, title string) basePage {
	nonce, ok := middleware.GetNonce(r.Context())
	if !ok {
		log.Printf("middleware.GetNonce: nonce was not set")
	}
	return basePage{
		Title: title,
		Query: searchQuery(r),
		Nonce: nonce,
	}
}

// GoogleAnalyticsTrackingID returns the tracking ID from
// func (b basePage) GoogleAnalyticsTrackingID() string {
	return "UA-141356704-1"
}

// AppVersionLabel uniquely identifies the currently running binary. It can be
// used for cache-busting query parameters.
func (b basePage) AppVersionLabel() string {
	return config.AppVersionLabel()
}

// errorPage contains fields for rendering a HTTP error page.
type errorPage struct {
	basePage
	Message          string
	SecondaryMessage template.HTML
}

func (s *Server) serveErrorPage(w http.ResponseWriter, r *http.Request, status int, page *errorPage) {
	if page == nil {
		page = &errorPage{
			basePage: newBasePage(r, ""),
		}
	}
	buf, err := s.renderErrorPage(status, page)
	if err != nil {
		log.Printf("s.renderErrorPage(w, %d, %v): %v", status, page, err)
		buf = s.errorPage
		status = http.StatusInternalServerError
	}

	w.WriteHeader(status)
	if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
		log.Printf("Error copying template %q buffer to ResponseWriter: %v", "error.tmpl", err)
	}
}

// renderErrorPage executes error.tmpl with the given errorPage
func (s *Server) renderErrorPage(status int, page *errorPage) ([]byte, error) {
	statusInfo := fmt.Sprintf("%d %s", status, http.StatusText(status))
	if page == nil {
		page = &errorPage{
			Message: statusInfo,
			basePage: basePage{
				Title: statusInfo,
			},
		}
	}
	if page.Message == "" {
		page.Message = statusInfo
	}
	if page.Title == "" {
		page.Title = statusInfo
	}
	return s.renderPage("error.tmpl", page)
}

// servePage is used to execute all templates for a *Server.
func (s *Server) servePage(w http.ResponseWriter, templateName string, page interface{}) {
	if s.reloadTemplates {
		s.mu.Lock()
		var err error
		s.templates, err = parsePageTemplates(s.templateDir)
		s.mu.Unlock()
		if err != nil {
			log.Printf("Error parsing templates: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	buf, err := s.renderPage(templateName, page)
	if err != nil {
		log.Printf("s.renderPage(%q, %v): %v", templateName, page, err)
		w.WriteHeader(http.StatusInternalServerError)
		buf = s.errorPage
	}
	if _, err := io.Copy(w, bytes.NewReader(buf)); err != nil {
		log.Printf("Error copying template %q buffer to ResponseWriter: %v", templateName, err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// renderPage executes the given templateName with page.
func (s *Server) renderPage(templateName string, page interface{}) ([]byte, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	var buf bytes.Buffer
	if err := s.templates[templateName].Execute(&buf, page); err != nil {
		log.Printf("Error executing page template %q: %v", templateName, err)
		return nil, err

	}
	return buf.Bytes(), nil
}

// parsePageTemplates parses html templates contained in the given base
// directory in order to generate a map of Name->*template.Template.
//
// Separate templates are used so that certain contextual functions (e.g.
// templateName) can be bound independently for each page.
func parsePageTemplates(base string) (map[string]*template.Template, error) {
	htmlSets := [][]string{
		{"index.tmpl"},
		{"error.tmpl"},
		{"search.tmpl"},
		{"advanced_search.tmpl"},
		{"copyright.tmpl"},
		{"license_policy.tmpl"},
		{"tos.tmpl"},
		{"doc.tmpl", "details.tmpl"},
		{"importedby.tmpl", "details.tmpl"},
		{"imports.tmpl", "details.tmpl"},
		{"licenses.tmpl", "details.tmpl"},
		{"module.tmpl", "details.tmpl"},
		{"readme.tmpl", "details.tmpl"},
		{"versions.tmpl", "details.tmpl"},
	}

	templates := make(map[string]*template.Template)
	for _, set := range htmlSets {
		t, err := template.New("base.tmpl").Funcs(template.FuncMap{
			"add":     func(i, j int) int { return i + j },
			"curYear": func() int { return time.Now().Year() },
			"pluralize": func(i int, s string) string {
				if i == 1 {
					return s
				}
				return s + "s"
			},
		}).ParseFiles(filepath.Join(base, "base.tmpl"))
		if err != nil {
			return nil, fmt.Errorf("ParseFiles: %v", err)
		}
		helperGlob := filepath.Join(base, "helpers", "*.tmpl")
		if _, err := t.ParseGlob(helperGlob); err != nil {
			return nil, fmt.Errorf("ParseGlob(%q): %v", helperGlob, err)
		}

		var files []string
		for _, f := range set {
			files = append(files, filepath.Join(base, "pages", f))
		}
		if _, err := t.ParseFiles(files...); err != nil {
			return nil, fmt.Errorf("ParseFiles(%v): %v", files, err)
		}
		templates[set[0]] = t
	}
	return templates, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 graphics

import (
	"strings"
)

type shaderID int

const (
	shaderVertexModelview shaderID = iota
	shaderFragmentNearest
	shaderFragmentLinear
	shaderFragmentScreen
)

func shader(id shaderID) string {
	if id == shaderVertexModelview {
		return shaderStrVertex
	}
	defs := []string{}
	switch id {
	case shaderFragmentNearest:
		defs = append(defs, "#define FILTER_NEAREST")
	case shaderFragmentLinear:
		defs = append(defs, "#define FILTER_LINEAR")
	case shaderFragmentScreen:
		defs = append(defs, "#define FILTER_SCREEN")
	default:
		panic("not reached")
	}
	return strings.Replace(shaderStrFragment, "{{Definitions}}", strings.Join(defs, "\n"), -1)
}

const (
	shaderStrVertex = `
uniform mat4 projection_matrix;
attribute vec2 vertex;
attribute vec4 tex_coord;
varying vec2 varying_tex_coord;
varying vec2 varying_tex_coord_min;
varying vec2 varying_tex_coord_max;

void main(void) {
  varying_tex_coord = vec2(tex_coord[0], tex_coord[1]);
  varying_tex_coord_min = vec2(min(tex_coord[0], tex_coord[2]), min(tex_coord[1], tex_coord[3]));
  varying_tex_coord_max = vec2(max(tex_coord[0], tex_coord[2]), max(tex_coord[1], tex_coord[3]));
  gl_Position = projection_matrix * vec4(vertex, 0, 1);
}
`
	shaderStrFragment = `
#if defined(GL_ES)
precision mediump float;
#else
#define lowp
#define mediump
#define highp
#endif

{{Definitions}}

uniform sampler2D texture;
uniform mat4 color_matrix;
uniform vec4 color_matrix_translation;

#if defined(FILTER_LINEAR) || defined(FILTER_SCREEN)
uniform highp vec2 source_size;
#endif

#if defined(FILTER_SCREEN)
uniform highp float scale;
#endif

varying highp vec2 varying_tex_coord;
varying highp vec2 varying_tex_coord_min;
varying highp vec2 varying_tex_coord_max;

highp vec2 roundTexel(highp vec2 p) {
  // highp (relative) precision is 2^(-16) in the spec.
  // The minimum value for a denominator is half of 65536.
  highp float factor = 1.0 / 32768.0;
  p.x -= mod(p.x + factor * 0.5, factor) - factor * 0.5;
  p.y -= mod(p.y + factor * 0.5, factor) - factor * 0.5;
  return p;
}

void main(void) {
  highp vec2 pos = varying_tex_coord;

#if defined(FILTER_NEAREST)
  vec4 color = texture2D(texture, pos);
  if (pos.x < varying_tex_coord_min.x ||
    pos.y < varying_tex_coord_min.y ||
    varying_tex_coord_max.x <= pos.x ||
    varying_tex_coord_max.y <= pos.y) {
    color = vec4(0, 0, 0, 0);
  }
#endif

#if defined(FILTER_LINEAR)
  pos = roundTexel(pos);
  highp vec2 texel_size = 1.0 / source_size;

  highp vec2 p0 = pos;
  highp vec2 p1 = pos + texel_size;
  vec4 c0 = texture2D(texture, p0);
  vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
  vec4 c2 = texture2D(texture, vec2(p0.x, p1.y));
  vec4 c3 = texture2D(texture, p1);
  if (p0.x < varying_tex_coord_min.x) {
    c0 = vec4(0, 0, 0, 0);
    c2 = vec4(0, 0, 0, 0);
  }
  if (p0.y < varying_tex_coord_min.y) {
    c0 = vec4(0, 0, 0, 0);
    c1 = vec4(0, 0, 0, 0);
  }
  if (varying_tex_coord_max.x <= p1.x) {
    c1 = vec4(0, 0, 0, 0);
    c3 = vec4(0, 0, 0, 0);
  }
  if (varying_tex_coord_max.y <= p1.y) {
    c2 = vec4(0, 0, 0, 0);
    c3 = vec4(0, 0, 0, 0);
  }

  vec2 rate = fract(pos * source_size);
  vec4 color = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
#endif

#if defined(FILTER_SCREEN)
  pos = roundTexel(pos);
  highp vec2 texel_size = 1.0 / source_size;

  highp vec2 p0 = pos;
  highp vec2 p1 = pos + texel_size / scale;
  vec4 c0 = texture2D(texture, p0);
  vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
  vec4 c2 = texture2D(texture, vec2(p0.x, p1.y));
  vec4 c3 = texture2D(texture, p1);
  // Texels must be in the source rect, so it is not necessary to check that like linear filter.

  vec2 rate = clamp((fract(pos * source_size) - vec2(0.5, 0.5)) * scale + vec2(0.5, 0.5), vec2(0.0, 0.), vec2(1.0, 1.0));
  vec4 color = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
#endif

  // Un-premultiply alpha
  if (0.0 < color.a) {
    color.rgb /= color.a;
  }
  // Apply the color matrix
  color = (color_matrix * color) + color_matrix_translation;
  color = clamp(color, 0.0, 1.0);
  // Premultiply alpha
  color.rgb *= color.a;

  gl_FragColor = color;
}
`
)
<commit_msg>graphics: Adjust texel positions for consitency<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 graphics

import (
	"strings"
)

type shaderID int

const (
	shaderVertexModelview shaderID = iota
	shaderFragmentNearest
	shaderFragmentLinear
	shaderFragmentScreen
)

func shader(id shaderID) string {
	if id == shaderVertexModelview {
		return shaderStrVertex
	}
	defs := []string{}
	switch id {
	case shaderFragmentNearest:
		defs = append(defs, "#define FILTER_NEAREST")
	case shaderFragmentLinear:
		defs = append(defs, "#define FILTER_LINEAR")
	case shaderFragmentScreen:
		defs = append(defs, "#define FILTER_SCREEN")
	default:
		panic("not reached")
	}
	return strings.Replace(shaderStrFragment, "{{Definitions}}", strings.Join(defs, "\n"), -1)
}

const (
	shaderStrVertex = `
uniform mat4 projection_matrix;
attribute vec2 vertex;
attribute vec4 tex_coord;
varying vec2 varying_tex_coord;
varying vec2 varying_tex_coord_min;
varying vec2 varying_tex_coord_max;

void main(void) {
  varying_tex_coord = vec2(tex_coord[0], tex_coord[1]);
  varying_tex_coord_min = vec2(min(tex_coord[0], tex_coord[2]), min(tex_coord[1], tex_coord[3]));
  varying_tex_coord_max = vec2(max(tex_coord[0], tex_coord[2]), max(tex_coord[1], tex_coord[3]));
  gl_Position = projection_matrix * vec4(vertex, 0, 1);
}
`
	shaderStrFragment = `
#if defined(GL_ES)
precision mediump float;
#else
#define lowp
#define mediump
#define highp
#endif

{{Definitions}}

uniform sampler2D texture;
uniform mat4 color_matrix;
uniform vec4 color_matrix_translation;

#if defined(FILTER_LINEAR) || defined(FILTER_SCREEN)
uniform highp vec2 source_size;
#endif

#if defined(FILTER_SCREEN)
uniform highp float scale;
#endif

varying highp vec2 varying_tex_coord;
varying highp vec2 varying_tex_coord_min;
varying highp vec2 varying_tex_coord_max;

highp vec2 roundTexel(highp vec2 p) {
  // highp (relative) precision is 2^(-16) in the spec.
  // The minimum value for a denominator is half of 65536.
  highp float factor = 1.0 / 32768.0;
  p.x -= mod(p.x + factor * 0.5, factor) - factor * 0.5;
  p.y -= mod(p.y + factor * 0.5, factor) - factor * 0.5;
  return p;
}

void main(void) {
  highp vec2 pos = varying_tex_coord;

#if defined(FILTER_NEAREST)
  vec4 color = texture2D(texture, pos);
  if (pos.x < varying_tex_coord_min.x ||
    pos.y < varying_tex_coord_min.y ||
    varying_tex_coord_max.x <= pos.x ||
    varying_tex_coord_max.y <= pos.y) {
    color = vec4(0, 0, 0, 0);
  }
#endif

#if defined(FILTER_LINEAR)
  pos = roundTexel(pos);
  highp vec2 texel_size = 1.0 / source_size;

  highp vec2 p0 = pos;
  highp vec2 p1 = pos + texel_size;
  vec4 c0 = texture2D(texture, p0);
  vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
  vec4 c2 = texture2D(texture, vec2(p0.x, p1.y));
  vec4 c3 = texture2D(texture, p1);
  if (p0.x < varying_tex_coord_min.x) {
    c0 = vec4(0, 0, 0, 0);
    c2 = vec4(0, 0, 0, 0);
  }
  if (p0.y < varying_tex_coord_min.y) {
    c0 = vec4(0, 0, 0, 0);
    c1 = vec4(0, 0, 0, 0);
  }
  if (varying_tex_coord_max.x <= p1.x) {
    c1 = vec4(0, 0, 0, 0);
    c3 = vec4(0, 0, 0, 0);
  }
  if (varying_tex_coord_max.y <= p1.y) {
    c2 = vec4(0, 0, 0, 0);
    c3 = vec4(0, 0, 0, 0);
  }

  vec2 rate = fract(pos * source_size);
  vec4 color = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
#endif

#if defined(FILTER_SCREEN)
  pos = roundTexel(pos);
  highp vec2 texel_size = 1.0 / source_size;
  pos -= texel_size * 0.5 * scale;

  highp vec2 p0 = pos;
  highp vec2 p1 = pos + texel_size / scale;
  vec4 c0 = texture2D(texture, p0);
  vec4 c1 = texture2D(texture, vec2(p1.x, p0.y));
  vec4 c2 = texture2D(texture, vec2(p0.x, p1.y));
  vec4 c3 = texture2D(texture, p1);
  // Texels must be in the source rect, so it is not necessary to check that like linear filter.

  vec2 rate = clamp((fract(pos * source_size) - vec2(0.5, 0.5)) * scale + vec2(0.5, 0.5), vec2(0.0, 0.), vec2(1.0, 1.0));
  vec4 color = mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y);
#endif

  // Un-premultiply alpha
  if (0.0 < color.a) {
    color.rgb /= color.a;
  }
  // Apply the color matrix
  color = (color_matrix * color) + color_matrix_translation;
  color = clamp(color, 0.0, 1.0);
  // Premultiply alpha
  color.rgb *= color.a;

  gl_FragColor = color;
}
`
)
<|endoftext|>


<commit_before>package internal

import (
	"github.com/kuzzleio/sdk-go/types"
	"github.com/stretchr/testify/mock"
	"time"
	"fmt"
	"reflect"
)

var OfflineQueue []types.QueryObject

type MockedConnection struct {
	mock.Mock
	MockSend      func([]byte, types.QueryOptions) types.KuzzleResponse
	MockEmitEvent func(int, interface{})
	MockGetRooms  func() types.RoomList
}

func (c MockedConnection) Send(query []byte, options types.QueryOptions, responseChannel chan<- types.KuzzleResponse, requestId string) error {
	if c.MockSend != nil {
		responseChannel <- c.MockSend(query, options)
	}

	return nil
}

func (c MockedConnection) Connect() (bool, error) {
	OfflineQueue = make([]types.QueryObject, 1)
	return false, nil
}

func (c MockedConnection) Close() error {
	return nil
}

func (c MockedConnection) AddListener(event int, channel chan<- interface{}) {}

func (c MockedConnection) GetState() *int {
	state := 0
	return &state
}

func (c MockedConnection) GetOfflineQueue() *[]types.QueryObject {
	return &OfflineQueue
}

func (c MockedConnection) EmitEvent(event int, arg interface{}) {
	if c.MockEmitEvent != nil {
		c.MockEmitEvent(event, arg)
	}
}

func (c MockedConnection) RegisterRoom(roomId, id string, room types.IRoom) {
}

func (c MockedConnection) UnregisterRoom(id string) {}

func (c MockedConnection) GetRequestHistory() *map[string]time.Time {
	r := make(map[string]time.Time)

	return &r
}

func (c MockedConnection) RenewSubscriptions() {}

func (c MockedConnection) GetRooms() *types.RoomList {
	v := c.MockGetRooms()

	return &v
}
<commit_msg>remove unused import<commit_after>package internal

import (
	"github.com/kuzzleio/sdk-go/types"
	"github.com/stretchr/testify/mock"
	"time"
)

var OfflineQueue []types.QueryObject

type MockedConnection struct {
	mock.Mock
	MockSend      func([]byte, types.QueryOptions) types.KuzzleResponse
	MockEmitEvent func(int, interface{})
	MockGetRooms  func() types.RoomList
}

func (c MockedConnection) Send(query []byte, options types.QueryOptions, responseChannel chan<- types.KuzzleResponse, requestId string) error {
	if c.MockSend != nil {
		responseChannel <- c.MockSend(query, options)
	}

	return nil
}

func (c MockedConnection) Connect() (bool, error) {
	OfflineQueue = make([]types.QueryObject, 1)
	return false, nil
}

func (c MockedConnection) Close() error {
	return nil
}

func (c MockedConnection) AddListener(event int, channel chan<- interface{}) {}

func (c MockedConnection) GetState() *int {
	state := 0
	return &state
}

func (c MockedConnection) GetOfflineQueue() *[]types.QueryObject {
	return &OfflineQueue
}

func (c MockedConnection) EmitEvent(event int, arg interface{}) {
	if c.MockEmitEvent != nil {
		c.MockEmitEvent(event, arg)
	}
}

func (c MockedConnection) RegisterRoom(roomId, id string, room types.IRoom) {
}

func (c MockedConnection) UnregisterRoom(id string) {}

func (c MockedConnection) GetRequestHistory() *map[string]time.Time {
	r := make(map[string]time.Time)

	return &r
}

func (c MockedConnection) RenewSubscriptions() {}

func (c MockedConnection) GetRooms() *types.RoomList {
	v := c.MockGetRooms()

	return &v
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package symbolz symbolizes a profile using the output from the symbolz
// service.
package symbolz

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"

	"github.com/google/pprof/internal/plugin"
	"github.com/google/pprof/profile"
)

var (
	symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
)

// Symbolize symbolizes profile p by parsing data returned by a
// symbolz handler. syms receives the symbolz query (hex addresses
// separated by '+') and returns the symbolz output in a string. If
// force is false, it will only symbolize locations from mappings
// not already marked as HasFunctions.
func Symbolize(p *profile.Profile, force bool, sources plugin.MappingSources, syms func(string, string) ([]byte, error), ui plugin.UI) error {
	for _, m := range p.Mapping {
		if !force && m.HasFunctions {
			// Only check for HasFunctions as symbolz only populates function names.
			continue
		}
		mappingSources := sources[m.File]
		if m.BuildID != "" {
			mappingSources = append(mappingSources, sources[m.BuildID]...)
		}
		for _, source := range mappingSources {
			if symz := symbolz(source.Source); symz != "" {
				if err := symbolizeMapping(symz, int64(source.Start)-int64(m.Start), syms, m, p); err != nil {
					return err
				}
				m.HasFunctions = true
				break
			}
		}
	}

	return nil
}

// Check whether path ends with one of the suffixes listed in
// pprof_remote_servers.html from the gperftools distribution
func hasGperftoolsSuffix(path string) bool {
	suffixes := []string{
		"/pprof/heap",
		"/pprof/growth",
		"/pprof/profile",
		"/pprof/pmuprofile",
		"/pprof/contention",
	}
	for _, s := range suffixes {
		if strings.HasSuffix(path, s) {
			return true
		}
	}
	return false
}

// symbolz returns the corresponding symbolz source for a profile URL.
func symbolz(source string) string {
	if url, err := url.Parse(source); err == nil && url.Host != "" {
		// All paths in the net/http/pprof Go package contain /debug/pprof/
		if strings.Contains(url.Path, "/debug/pprof/") || hasGperftoolsSuffix(url.Path) {
			url.Path = path.Clean(url.Path + "/../symbol")
		} else {
			url.Path = "/symbolz"
		}
		url.RawQuery = ""
		return url.String()
	}

	return ""
}

// symbolizeMapping symbolizes locations belonging to a Mapping by querying
// a symbolz handler. An offset is applied to all addresses to take care of
// normalization occurred for merged Mappings.
func symbolizeMapping(source string, offset int64, syms func(string, string) ([]byte, error), m *profile.Mapping, p *profile.Profile) error {
	// Construct query of addresses to symbolize.
	var a []string
	for _, l := range p.Location {
		if l.Mapping == m && l.Address != 0 && len(l.Line) == 0 {
			// Compensate for normalization.
			addr := int64(l.Address) + offset
			if addr < 0 {
				return fmt.Errorf("unexpected negative adjusted address, mapping %v source %d, offset %d", l.Mapping, l.Address, offset)
			}
			a = append(a, fmt.Sprintf("%#x", addr))
		}
	}

	if len(a) == 0 {
		// No addresses to symbolize.
		return nil
	}

	lines := make(map[uint64]profile.Line)
	functions := make(map[string]*profile.Function)

	b, err := syms(source, strings.Join(a, "+"))
	if err != nil {
		return err
	}

	buf := bytes.NewBuffer(b)
	for {
		l, err := buf.ReadString('\n')

		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
			addr, err := strconv.ParseInt(symbol[1], 0, 64)
			if err != nil {
				return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
			}
			if addr < 0 {
				return fmt.Errorf("unexpected negative adjusted address, source %s, offset %d", symbol[1], offset)
			}
			// Reapply offset expected by the profile.
			addr -= offset

			name := symbol[2]
			fn := functions[name]
			if fn == nil {
				fn = &profile.Function{
					ID:         uint64(len(p.Function) + 1),
					Name:       name,
					SystemName: name,
				}
				functions[name] = fn
				p.Function = append(p.Function, fn)
			}

			lines[uint64(addr)] = profile.Line{Function: fn}
		}
	}

	for _, l := range p.Location {
		if l.Mapping != m {
			continue
		}
		if line, ok := lines[l.Address]; ok {
			l.Line = []profile.Line{line}
		}
	}

	return nil
}
<commit_msg>Skip unsymbolizable mapping during symbolz pass. (#368)<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package symbolz symbolizes a profile using the output from the symbolz
// service.
package symbolz

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"

	"github.com/google/pprof/internal/plugin"
	"github.com/google/pprof/profile"
)

var (
	symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
)

// Symbolize symbolizes profile p by parsing data returned by a symbolz
// handler. syms receives the symbolz query (hex addresses separated by '+')
// and returns the symbolz output in a string. If force is false, it will only
// symbolize locations from mappings not already marked as HasFunctions. Never
// attempts symbolization of addresses from unsymbolizable system
// mappings as those may look negative - e.g. "[vsyscall]".
func Symbolize(p *profile.Profile, force bool, sources plugin.MappingSources, syms func(string, string) ([]byte, error), ui plugin.UI) error {
	for _, m := range p.Mapping {
		if !force && m.HasFunctions {
			// Only check for HasFunctions as symbolz only populates function names.
			continue
		}
		// Skip well-known system mappings.
		if m.Unsymbolizable() {
			continue
		}
		mappingSources := sources[m.File]
		if m.BuildID != "" {
			mappingSources = append(mappingSources, sources[m.BuildID]...)
		}
		for _, source := range mappingSources {
			if symz := symbolz(source.Source); symz != "" {
				if err := symbolizeMapping(symz, int64(source.Start)-int64(m.Start), syms, m, p); err != nil {
					return err
				}
				m.HasFunctions = true
				break
			}
		}
	}

	return nil
}

// Check whether path ends with one of the suffixes listed in
// pprof_remote_servers.html from the gperftools distribution
func hasGperftoolsSuffix(path string) bool {
	suffixes := []string{
		"/pprof/heap",
		"/pprof/growth",
		"/pprof/profile",
		"/pprof/pmuprofile",
		"/pprof/contention",
	}
	for _, s := range suffixes {
		if strings.HasSuffix(path, s) {
			return true
		}
	}
	return false
}

// symbolz returns the corresponding symbolz source for a profile URL.
func symbolz(source string) string {
	if url, err := url.Parse(source); err == nil && url.Host != "" {
		// All paths in the net/http/pprof Go package contain /debug/pprof/
		if strings.Contains(url.Path, "/debug/pprof/") || hasGperftoolsSuffix(url.Path) {
			url.Path = path.Clean(url.Path + "/../symbol")
		} else {
			url.Path = "/symbolz"
		}
		url.RawQuery = ""
		return url.String()
	}

	return ""
}

// symbolizeMapping symbolizes locations belonging to a Mapping by querying
// a symbolz handler. An offset is applied to all addresses to take care of
// normalization occurred for merged Mappings.
func symbolizeMapping(source string, offset int64, syms func(string, string) ([]byte, error), m *profile.Mapping, p *profile.Profile) error {
	// Construct query of addresses to symbolize.
	var a []string
	for _, l := range p.Location {
		if l.Mapping == m && l.Address != 0 && len(l.Line) == 0 {
			// Compensate for normalization.
			addr := int64(l.Address) + offset
			if addr < 0 {
				return fmt.Errorf("unexpected negative adjusted address, mapping %v source %d, offset %d", l.Mapping, l.Address, offset)
			}
			a = append(a, fmt.Sprintf("%#x", addr))
		}
	}

	if len(a) == 0 {
		// No addresses to symbolize.
		return nil
	}

	lines := make(map[uint64]profile.Line)
	functions := make(map[string]*profile.Function)

	b, err := syms(source, strings.Join(a, "+"))
	if err != nil {
		return err
	}

	buf := bytes.NewBuffer(b)
	for {
		l, err := buf.ReadString('\n')

		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
			addr, err := strconv.ParseInt(symbol[1], 0, 64)
			if err != nil {
				return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
			}
			if addr < 0 {
				return fmt.Errorf("unexpected negative adjusted address, source %s, offset %d", symbol[1], offset)
			}
			// Reapply offset expected by the profile.
			addr -= offset

			name := symbol[2]
			fn := functions[name]
			if fn == nil {
				fn = &profile.Function{
					ID:         uint64(len(p.Function) + 1),
					Name:       name,
					SystemName: name,
				}
				functions[name] = fn
				p.Function = append(p.Function, fn)
			}

			lines[uint64(addr)] = profile.Line{Function: fn}
		}
	}

	for _, l := range p.Location {
		if l.Mapping != m {
			continue
		}
		if line, ok := lines[l.Address]; ok {
			l.Line = []profile.Line{line}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"
	"github.com/privacybydesign/gabi/keyproof"
	"github.com/privacybydesign/irmago/internal/common"
	"github.com/sietseringers/cobra"
)

type stepStartMessage struct {
	desc          string
	intermediates int
}
type stepDoneMessage struct{}
type tickMessage struct{}
type quitMessage struct{}
type finishMessage struct{}
type setFinalMessage struct {
	message string
}

type logFollower struct {
	stepStartEvents chan<- stepStartMessage
	stepDoneEvents  chan<- stepDoneMessage
	tickEvents      chan<- tickMessage
	quitEvents      chan<- quitMessage
	finalEvents     chan<- setFinalMessage
	finished        <-chan finishMessage
}

func (l *logFollower) StepStart(desc string, intermediates int) {
	l.stepStartEvents <- stepStartMessage{desc, intermediates}
}

func (l *logFollower) StepDone() {
	l.stepDoneEvents <- stepDoneMessage{}
}

func (l *logFollower) Tick() {
	l.tickEvents <- tickMessage{}
}

func (l *logFollower) Quit() {
	l.quitEvents <- quitMessage{}
}

func printProofStatus(status string, count, limit int, done bool) {
	var tail string
	if done {
		tail = "done"
	} else if limit > 0 {
		tail = fmt.Sprintf("%v/%v", count, limit)
	} else {
		tail = ""
	}

	tlen := len(tail)
	if tlen == 0 {
		tlen = 4
	}

	fmt.Printf("\r%s%s%s", status, strings.Repeat(".", 60-len(status)-tlen), tail)
}

func startLogFollower() *logFollower {
	var result = new(logFollower)

	starts := make(chan stepStartMessage)
	dones := make(chan stepDoneMessage)
	ticks := make(chan tickMessage)
	quit := make(chan quitMessage)
	finished := make(chan finishMessage)
	finalmessage := make(chan setFinalMessage)

	result.stepStartEvents = starts
	result.stepDoneEvents = dones
	result.tickEvents = ticks
	result.quitEvents = quit
	result.finished = finished
	result.finalEvents = finalmessage

	go func() {
		doneMissing := 0
		curStatus := ""
		curCount := 0
		curLimit := 0
		curDone := true
		finalMessage := ""
		ticker := time.NewTicker(time.Second / 4)
		defer ticker.Stop()

		for {
			select {
			case <-ticks:
				curCount++
			case <-dones:
				if doneMissing > 0 {
					doneMissing--
					continue // Swallow quietly
				} else {
					curDone = true
					printProofStatus(curStatus, curCount, curLimit, true)
					fmt.Printf("\n")
				}
			case stepstart := <-starts:
				if !curDone {
					printProofStatus(curStatus, curCount, curLimit, true)
					fmt.Printf("\n")
					doneMissing++
				}
				curDone = false
				curCount = 0
				curLimit = stepstart.intermediates
				curStatus = stepstart.desc
			case messageevent := <-finalmessage:
				finalMessage = messageevent.message
			case <-quit:
				if finalMessage != "" {
					fmt.Printf("%s\n", finalMessage)
				}
				finished <- finishMessage{}
				return
			case <-ticker.C:
				if !curDone {
					printProofStatus(curStatus, curCount, curLimit, false)
				}
			}
		}
	}()

	keyproof.Follower = result

	return result
}

var issuerKeyproveCmd = &cobra.Command{
	Use:   "keyprove [path]",
	Short: "Generate proof of correct generation for an IRMA issuer keypair",
	Long: `Generate proof of correct generation for an IRMA issuer keypair.

The keyprove command generates a proof that an issuer key was generated correctly. By default, it generates a proof for the newest private key in the PrivateKeys folder, and then stores the proof in the Proofs folder.`,
	Args: cobra.MaximumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		flags := cmd.Flags()
		counter, _ := flags.GetUint("counter")
		pubkeyfile, _ := flags.GetString("publickey")
		privkeyfile, _ := flags.GetString("privatekey")
		prooffile, _ := flags.GetString("proof")

		var err error

		// Determine path for key
		var path string
		if len(args) != 0 {
			path = args[0]
		} else {
			path, err = os.Getwd()
			if err != nil {
				die("", err)
			}
		}
		if err = common.AssertPathExists(path); err != nil {
			die("Nonexisting path specified", err)
		}

		// Determine counter if needed
		if !flags.Changed("counter") {
			counter = uint(lastPrivateKeyIndex(path))
		}

		// Fill in pubkey if needed
		if pubkeyfile == "" {
			pubkeyfile = filepath.Join(path, "PublicKeys", strconv.Itoa(int(counter))+".xml")
		}

		// Fill in privkey if needed
		if privkeyfile == "" {
			privkeyfile = filepath.Join(path, "PrivateKeys", strconv.Itoa(int(counter))+".xml")
		}

		// Try to read public key
		pk, err := gabi.NewPublicKeyFromFile(pubkeyfile)
		if err != nil {
			die("Could not read public key", err)
		}

		// Try to read private key
		sk, err := gabi.NewPrivateKeyFromFile(privkeyfile, false)
		if err != nil {
			die("Could not read private key", err)
		}

		// Validate that they match
		if pk.N.Cmp(new(big.Int).Mul(sk.P, sk.Q)) != 0 {
			die("Private and public key do not match", nil)
		}

		// Validate that the key is amenable to proving
		ConstEight := big.NewInt(8)
		ConstOne := big.NewInt(1)
		PMod := new(big.Int).Mod(sk.P, ConstEight)
		QMod := new(big.Int).Mod(sk.Q, ConstEight)
		PPrimeMod := new(big.Int).Mod(sk.PPrime, ConstEight)
		QPrimeMod := new(big.Int).Mod(sk.QPrime, ConstEight)
		if PMod.Cmp(ConstOne) == 0 || QMod.Cmp(ConstOne) == 0 ||
			PPrimeMod.Cmp(ConstOne) == 0 || QPrimeMod.Cmp(ConstOne) == 0 ||
			PMod.Cmp(QMod) == 0 || PPrimeMod.Cmp(QPrimeMod) == 0 {
			die("Private key not amenable to proving", nil)
		}

		// Prepare storage for proof if needed
		if prooffile == "" {
			proofpath := filepath.Join(path, "Proofs")
			if err = common.EnsureDirectoryExists(proofpath); err != nil {
				die("Failed to create"+proofpath, err)
			}
			prooffile = filepath.Join(proofpath, strconv.Itoa(int(counter))+".json.gz")
		}

		// Open proof file for writing
		proofOut, err := os.Create(prooffile)
		if err != nil {
			die("Error opening proof file for writing", err)
		}
		defer proofOut.Close()

		// Wrap it for gzip compression
		proofWriter := gzip.NewWriter(proofOut)
		defer proofWriter.Close()

		// Start log follower
		follower := startLogFollower()
		defer func() {
			follower.quitEvents <- quitMessage{}
			<-follower.finished
		}()

		// Build the proof
		s := keyproof.NewValidKeyProofStructure(pk.N, pk.Z, pk.S, pk.R)
		proof := s.BuildProof(sk.PPrime, sk.QPrime)

		// And write it to file
		follower.StepStart("Writing proof", 0)
		proofEncoder := json.NewEncoder(proofWriter)
		err = proofEncoder.Encode(proof)
		follower.StepDone()
		if err != nil {
			die("Could not write proof", err)
		}
	},
}

func init() {
	issuerCmd.AddCommand(issuerKeyproveCmd)

	issuerKeyproveCmd.Flags().StringP("privatekey", "s", "", `File to get private key from (default "PrivateKeys/$counter.xml")`)
	issuerKeyproveCmd.Flags().StringP("publickey", "p", "", `File to get public key from (default "PublicKeys/$counter.xml")`)
	issuerKeyproveCmd.Flags().StringP("proof", "o", "", `File to write proof to (default "Proofs/$index.json.gz")`)
	issuerKeyproveCmd.Flags().UintP("counter", "c", 0, "Counter of key to prove (default to latest)")
}
<commit_msg>refactor: remove unused function in keyproof<commit_after>package cmd

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"
	"github.com/privacybydesign/gabi/keyproof"
	"github.com/privacybydesign/irmago/internal/common"
	"github.com/sietseringers/cobra"
)

type stepStartMessage struct {
	desc          string
	intermediates int
}
type stepDoneMessage struct{}
type tickMessage struct{}
type quitMessage struct{}
type finishMessage struct{}
type setFinalMessage struct {
	message string
}

type logFollower struct {
	stepStartEvents chan<- stepStartMessage
	stepDoneEvents  chan<- stepDoneMessage
	tickEvents      chan<- tickMessage
	quitEvents      chan<- quitMessage
	finalEvents     chan<- setFinalMessage
	finished        <-chan finishMessage
}

func (l *logFollower) StepStart(desc string, intermediates int) {
	l.stepStartEvents <- stepStartMessage{desc, intermediates}
}

func (l *logFollower) StepDone() {
	l.stepDoneEvents <- stepDoneMessage{}
}

func (l *logFollower) Tick() {
	l.tickEvents <- tickMessage{}
}

func printProofStatus(status string, count, limit int, done bool) {
	var tail string
	if done {
		tail = "done"
	} else if limit > 0 {
		tail = fmt.Sprintf("%v/%v", count, limit)
	} else {
		tail = ""
	}

	tlen := len(tail)
	if tlen == 0 {
		tlen = 4
	}

	fmt.Printf("\r%s%s%s", status, strings.Repeat(".", 60-len(status)-tlen), tail)
}

func startLogFollower() *logFollower {
	var result = new(logFollower)

	starts := make(chan stepStartMessage)
	dones := make(chan stepDoneMessage)
	ticks := make(chan tickMessage)
	quit := make(chan quitMessage)
	finished := make(chan finishMessage)
	finalmessage := make(chan setFinalMessage)

	result.stepStartEvents = starts
	result.stepDoneEvents = dones
	result.tickEvents = ticks
	result.quitEvents = quit
	result.finished = finished
	result.finalEvents = finalmessage

	go func() {
		doneMissing := 0
		curStatus := ""
		curCount := 0
		curLimit := 0
		curDone := true
		finalMessage := ""
		ticker := time.NewTicker(time.Second / 4)
		defer ticker.Stop()

		for {
			select {
			case <-ticks:
				curCount++
			case <-dones:
				if doneMissing > 0 {
					doneMissing--
					continue // Swallow quietly
				} else {
					curDone = true
					printProofStatus(curStatus, curCount, curLimit, true)
					fmt.Printf("\n")
				}
			case stepstart := <-starts:
				if !curDone {
					printProofStatus(curStatus, curCount, curLimit, true)
					fmt.Printf("\n")
					doneMissing++
				}
				curDone = false
				curCount = 0
				curLimit = stepstart.intermediates
				curStatus = stepstart.desc
			case messageevent := <-finalmessage:
				finalMessage = messageevent.message
			case <-quit:
				if finalMessage != "" {
					fmt.Printf("%s\n", finalMessage)
				}
				finished <- finishMessage{}
				return
			case <-ticker.C:
				if !curDone {
					printProofStatus(curStatus, curCount, curLimit, false)
				}
			}
		}
	}()

	keyproof.Follower = result

	return result
}

var issuerKeyproveCmd = &cobra.Command{
	Use:   "keyprove [path]",
	Short: "Generate proof of correct generation for an IRMA issuer keypair",
	Long: `Generate proof of correct generation for an IRMA issuer keypair.

The keyprove command generates a proof that an issuer key was generated correctly. By default, it generates a proof for the newest private key in the PrivateKeys folder, and then stores the proof in the Proofs folder.`,
	Args: cobra.MaximumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		flags := cmd.Flags()
		counter, _ := flags.GetUint("counter")
		pubkeyfile, _ := flags.GetString("publickey")
		privkeyfile, _ := flags.GetString("privatekey")
		prooffile, _ := flags.GetString("proof")

		var err error

		// Determine path for key
		var path string
		if len(args) != 0 {
			path = args[0]
		} else {
			path, err = os.Getwd()
			if err != nil {
				die("", err)
			}
		}
		if err = common.AssertPathExists(path); err != nil {
			die("Nonexisting path specified", err)
		}

		// Determine counter if needed
		if !flags.Changed("counter") {
			counter = uint(lastPrivateKeyIndex(path))
		}

		// Fill in pubkey if needed
		if pubkeyfile == "" {
			pubkeyfile = filepath.Join(path, "PublicKeys", strconv.Itoa(int(counter))+".xml")
		}

		// Fill in privkey if needed
		if privkeyfile == "" {
			privkeyfile = filepath.Join(path, "PrivateKeys", strconv.Itoa(int(counter))+".xml")
		}

		// Try to read public key
		pk, err := gabi.NewPublicKeyFromFile(pubkeyfile)
		if err != nil {
			die("Could not read public key", err)
		}

		// Try to read private key
		sk, err := gabi.NewPrivateKeyFromFile(privkeyfile, false)
		if err != nil {
			die("Could not read private key", err)
		}

		// Validate that they match
		if pk.N.Cmp(new(big.Int).Mul(sk.P, sk.Q)) != 0 {
			die("Private and public key do not match", nil)
		}

		// Validate that the key is amenable to proving
		ConstEight := big.NewInt(8)
		ConstOne := big.NewInt(1)
		PMod := new(big.Int).Mod(sk.P, ConstEight)
		QMod := new(big.Int).Mod(sk.Q, ConstEight)
		PPrimeMod := new(big.Int).Mod(sk.PPrime, ConstEight)
		QPrimeMod := new(big.Int).Mod(sk.QPrime, ConstEight)
		if PMod.Cmp(ConstOne) == 0 || QMod.Cmp(ConstOne) == 0 ||
			PPrimeMod.Cmp(ConstOne) == 0 || QPrimeMod.Cmp(ConstOne) == 0 ||
			PMod.Cmp(QMod) == 0 || PPrimeMod.Cmp(QPrimeMod) == 0 {
			die("Private key not amenable to proving", nil)
		}

		// Prepare storage for proof if needed
		if prooffile == "" {
			proofpath := filepath.Join(path, "Proofs")
			if err = common.EnsureDirectoryExists(proofpath); err != nil {
				die("Failed to create"+proofpath, err)
			}
			prooffile = filepath.Join(proofpath, strconv.Itoa(int(counter))+".json.gz")
		}

		// Open proof file for writing
		proofOut, err := os.Create(prooffile)
		if err != nil {
			die("Error opening proof file for writing", err)
		}
		defer proofOut.Close()

		// Wrap it for gzip compression
		proofWriter := gzip.NewWriter(proofOut)
		defer proofWriter.Close()

		// Start log follower
		follower := startLogFollower()
		defer func() {
			follower.quitEvents <- quitMessage{}
			<-follower.finished
		}()

		// Build the proof
		s := keyproof.NewValidKeyProofStructure(pk.N, pk.Z, pk.S, pk.R)
		proof := s.BuildProof(sk.PPrime, sk.QPrime)

		// And write it to file
		follower.StepStart("Writing proof", 0)
		proofEncoder := json.NewEncoder(proofWriter)
		err = proofEncoder.Encode(proof)
		follower.StepDone()
		if err != nil {
			die("Could not write proof", err)
		}
	},
}

func init() {
	issuerCmd.AddCommand(issuerKeyproveCmd)

	issuerKeyproveCmd.Flags().StringP("privatekey", "s", "", `File to get private key from (default "PrivateKeys/$counter.xml")`)
	issuerKeyproveCmd.Flags().StringP("publickey", "p", "", `File to get public key from (default "PublicKeys/$counter.xml")`)
	issuerKeyproveCmd.Flags().StringP("proof", "o", "", `File to write proof to (default "Proofs/$index.json.gz")`)
	issuerKeyproveCmd.Flags().UintP("counter", "c", 0, "Counter of key to prove (default to latest)")
}
<|endoftext|>


<commit_before>// Copyright 2018 Prometheus Team
// 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 cli

import (
	"context"
	"errors"
	"fmt"
	"time"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-openapi/strfmt"
	"github.com/prometheus/alertmanager/api/v2/client/silence"
	"github.com/prometheus/alertmanager/api/v2/models"
	"github.com/prometheus/alertmanager/cli/format"
	"github.com/prometheus/common/model"
)

type silenceUpdateCmd struct {
	quiet    bool
	duration string
	start    string
	end      string
	comment  string
	ids      []string
}

func configureSilenceUpdateCmd(cc *kingpin.CmdClause) {
	var (
		c         = &silenceUpdateCmd{}
		updateCmd = cc.Command("update", "Update silences")
	)
	updateCmd.Flag("quiet", "Only show silence ids").Short('q').BoolVar(&c.quiet)
	updateCmd.Flag("duration", "Duration of silence").Short('d').StringVar(&c.duration)
	updateCmd.Flag("start", "Set when the silence should start. RFC3339 format 2006-01-02T15:04:05-07:00").StringVar(&c.start)
	updateCmd.Flag("end", "Set when the silence should end (overwrites duration). RFC3339 format 2006-01-02T15:04:05-07:00").StringVar(&c.end)
	updateCmd.Flag("comment", "A comment to help describe the silence").Short('c').StringVar(&c.comment)
	updateCmd.Arg("update-ids", "Silence IDs to update").StringsVar(&c.ids)

	updateCmd.Action(execWithTimeout(c.update))
}

func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext) error {
	if len(c.ids) < 1 {
		return fmt.Errorf("no silence IDs specified")
	}

	amclient := NewAlertmanagerClient(alertmanagerURL)

	var updatedSilences []models.GettableSilence
	for _, silenceID := range c.ids {
		params := silence.NewGetSilenceParams()
		params.SilenceID = strfmt.UUID(silenceID)
		response, err := amclient.Silence.GetSilence(params)
		sil := response.Payload
		if err != nil {
			return err
		}
		if c.start != "" {
			startsAtTime, err := time.Parse(time.RFC3339, c.start)
			if err != nil {
				return err
			}
			startsAt := strfmt.DateTime(startsAtTime)
			sil.StartsAt = &startsAt
		}

		if c.end != "" {
			endsAtTime, err := time.Parse(time.RFC3339, c.end)
			if err != nil {
				return err
			}
			endsAt := strfmt.DateTime(endsAtTime)
			sil.EndsAt = &endsAt
		} else if c.duration != "" {
			d, err := model.ParseDuration(c.duration)
			if err != nil {
				return err
			}
			if d == 0 {
				return fmt.Errorf("silence duration must be greater than 0")
			}
			endsAt := strfmt.DateTime(time.Time(*sil.StartsAt).UTC().Add(time.Duration(d)))
			sil.EndsAt = &endsAt
		}

		if time.Time(*sil.StartsAt).After(time.Time(*sil.EndsAt)) {
			return errors.New("silence cannot start after it ends")
		}

		if c.comment != "" {
			sil.Comment = &c.comment
		}

		ps := &models.PostableSilence{
			ID:      *sil.ID,
			Silence: sil.Silence,
		}

		amclient := NewAlertmanagerClient(alertmanagerURL)

		silenceParams := silence.NewPostSilencesParams().WithContext(ctx).WithSilence(ps)
		postOk, err := amclient.Silence.PostSilences(silenceParams)
		if err != nil {
			return err
		}

		sil.ID = &postOk.Payload.SilenceID
		updatedSilences = append(updatedSilences, *sil)
	}

	if c.quiet {
		for _, silence := range updatedSilences {
			fmt.Println(silence.ID)
		}
	} else {
		formatter, found := format.Formatters[output]
		if !found {
			return fmt.Errorf("unknown output formatter")
		}
		if err := formatter.FormatSilences(updatedSilences); err != nil {
			return fmt.Errorf("error formatting silences: %v", err)
		}
	}
	return nil
}
<commit_msg>cli: avoid nil dereference in silence update (#2427)<commit_after>// Copyright 2018 Prometheus Team
// 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 cli

import (
	"context"
	"errors"
	"fmt"
	"time"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-openapi/strfmt"
	"github.com/prometheus/alertmanager/api/v2/client/silence"
	"github.com/prometheus/alertmanager/api/v2/models"
	"github.com/prometheus/alertmanager/cli/format"
	"github.com/prometheus/common/model"
)

type silenceUpdateCmd struct {
	quiet    bool
	duration string
	start    string
	end      string
	comment  string
	ids      []string
}

func configureSilenceUpdateCmd(cc *kingpin.CmdClause) {
	var (
		c         = &silenceUpdateCmd{}
		updateCmd = cc.Command("update", "Update silences")
	)
	updateCmd.Flag("quiet", "Only show silence ids").Short('q').BoolVar(&c.quiet)
	updateCmd.Flag("duration", "Duration of silence").Short('d').StringVar(&c.duration)
	updateCmd.Flag("start", "Set when the silence should start. RFC3339 format 2006-01-02T15:04:05-07:00").StringVar(&c.start)
	updateCmd.Flag("end", "Set when the silence should end (overwrites duration). RFC3339 format 2006-01-02T15:04:05-07:00").StringVar(&c.end)
	updateCmd.Flag("comment", "A comment to help describe the silence").Short('c').StringVar(&c.comment)
	updateCmd.Arg("update-ids", "Silence IDs to update").StringsVar(&c.ids)

	updateCmd.Action(execWithTimeout(c.update))
}

func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext) error {
	if len(c.ids) < 1 {
		return fmt.Errorf("no silence IDs specified")
	}

	amclient := NewAlertmanagerClient(alertmanagerURL)

	var updatedSilences []models.GettableSilence
	for _, silenceID := range c.ids {
		params := silence.NewGetSilenceParams()
		params.SilenceID = strfmt.UUID(silenceID)
		response, err := amclient.Silence.GetSilence(params)
		if err != nil {
			return err
		}
		sil := response.Payload
		if c.start != "" {
			startsAtTime, err := time.Parse(time.RFC3339, c.start)
			if err != nil {
				return err
			}
			startsAt := strfmt.DateTime(startsAtTime)
			sil.StartsAt = &startsAt
		}

		if c.end != "" {
			endsAtTime, err := time.Parse(time.RFC3339, c.end)
			if err != nil {
				return err
			}
			endsAt := strfmt.DateTime(endsAtTime)
			sil.EndsAt = &endsAt
		} else if c.duration != "" {
			d, err := model.ParseDuration(c.duration)
			if err != nil {
				return err
			}
			if d == 0 {
				return fmt.Errorf("silence duration must be greater than 0")
			}
			endsAt := strfmt.DateTime(time.Time(*sil.StartsAt).UTC().Add(time.Duration(d)))
			sil.EndsAt = &endsAt
		}

		if time.Time(*sil.StartsAt).After(time.Time(*sil.EndsAt)) {
			return errors.New("silence cannot start after it ends")
		}

		if c.comment != "" {
			sil.Comment = &c.comment
		}

		ps := &models.PostableSilence{
			ID:      *sil.ID,
			Silence: sil.Silence,
		}

		amclient := NewAlertmanagerClient(alertmanagerURL)

		silenceParams := silence.NewPostSilencesParams().WithContext(ctx).WithSilence(ps)
		postOk, err := amclient.Silence.PostSilences(silenceParams)
		if err != nil {
			return err
		}

		sil.ID = &postOk.Payload.SilenceID
		updatedSilences = append(updatedSilences, *sil)
	}

	if c.quiet {
		for _, silence := range updatedSilences {
			fmt.Println(silence.ID)
		}
	} else {
		formatter, found := format.Formatters[output]
		if !found {
			return fmt.Errorf("unknown output formatter")
		}
		if err := formatter.FormatSilences(updatedSilences); err != nil {
			return fmt.Errorf("error formatting silences: %v", err)
		}
	}
	return nil
}
<|endoftext|>