<commit_before>/*
Copyright 2019 The Knative 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 metrics

import (
	"fmt"
	"os"
	texttemplate "text/template"

	corev1 "k8s.io/api/core/v1"
	cm "knative.dev/pkg/configmap"
)

const (
	// The following is used to set the default log url template
	DefaultLogURLTemplate = ""

	// DefaultRequestLogTemplate is the default format for emitting request logs.
	DefaultRequestLogTemplate = `{"httpRequest": {"requestMethod": "{{.Request.Method}}", "requestUrl": "{{js .Request.RequestURI}}", "requestSize": "{{.Request.ContentLength}}", "status": {{.Response.Code}}, "responseSize": "{{.Response.Size}}", "userAgent": "{{js .Request.UserAgent}}", "remoteIp": "{{js .Request.RemoteAddr}}", "serverIp": "{{.Revision.PodIP}}", "referer": "{{js .Request.Referer}}", "latency": "{{.Response.Latency}}s", "protocol": "{{.Request.Proto}}"}, "traceId": "{{index .Request.Header "X-B3-Traceid"}}"}`

	// The following is used to set the default metrics backend
	defaultRequestMetricsBackend = "prometheus"

	// The env var name for config-observability
	configMapNameEnv = "CONFIG_OBSERVABILITY_NAME"

	// ReqLogTemplateKey is the CM key for the request log template.
	ReqLogTemplateKey = "logging.request-log-template"

	// EnableReqLogKey is the CM key to enable request log.
	EnableReqLogKey = "logging.enable-request-log"

	// EnableProbeReqLogKey is the CM key to enable request logs for probe requests.
	EnableProbeReqLogKey = "logging.enable-probe-request-log"
)

// ObservabilityConfig contains the configuration defined in the observability ConfigMap.
// +k8s:deepcopy-gen=true
type ObservabilityConfig struct {
	// EnableVarLogCollection specifies whether the logs under /var/log/ should be available
	// for collection on the host node by the fluentd daemon set.
	EnableVarLogCollection bool

	// LoggingURLTemplate is a string containing the logging url template where
	// the variable REVISION_UID will be replaced with the created revision's UID.
	LoggingURLTemplate string

	// RequestLogTemplate is the go template to use to shape the request logs.
	RequestLogTemplate string

	// EnableProbeRequestLog enables queue-proxy to write health check probe request logs.
	EnableProbeRequestLog bool

	// RequestMetricsBackend specifies the request metrics destination, e.g. Prometheus,
	// Stackdriver. "None" disables all backends.
	RequestMetricsBackend string

	// EnableProfiling indicates whether it is allowed to retrieve runtime profiling data from
	// the pods via an HTTP server in the format expected by the pprof visualization tool.
	EnableProfiling bool

	// EnableRequestLog enables activator/queue-proxy to write request logs.
	EnableRequestLog bool

	// MetricsCollectorAddress specifies the metrics collector address. This is only used
	// when the metrics backend is opencensus.
	MetricsCollectorAddress string
}

func defaultConfig() *ObservabilityConfig {
	return &ObservabilityConfig{
		LoggingURLTemplate:    DefaultLogURLTemplate,
		RequestLogTemplate:    DefaultRequestLogTemplate,
		RequestMetricsBackend: defaultRequestMetricsBackend,
	}
}

// NewObservabilityConfigFromConfigMap creates a ObservabilityConfig from the supplied ConfigMap
func NewObservabilityConfigFromConfigMap(configMap *corev1.ConfigMap) (*ObservabilityConfig, error) {
	oc := defaultConfig()

	if err := cm.Parse(configMap.Data,
		cm.AsBool("logging.enable-var-log-collection", &oc.EnableVarLogCollection),
		cm.AsString("logging.revision-url-template", &oc.LoggingURLTemplate),
		cm.AsString(ReqLogTemplateKey, &oc.RequestLogTemplate),
		cm.AsBool(EnableReqLogKey, &oc.EnableRequestLog),
		cm.AsBool(EnableProbeReqLogKey, &oc.EnableProbeRequestLog),
		cm.AsString("metrics.request-metrics-backend-destination", &oc.RequestMetricsBackend),
		cm.AsBool("profiling.enable", &oc.EnableProfiling),
		cm.AsString("metrics.opencensus-address", &oc.MetricsCollectorAddress),
	); err != nil {
		return nil, err
	}

	if oc.RequestLogTemplate == "" && oc.EnableRequestLog {
		return nil, fmt.Errorf("%q was set to true, but no %q was specified", EnableReqLogKey, ReqLogTemplateKey)
	}

	if oc.RequestLogTemplate != "" {
		// Verify that we get valid templates.
		if _, err := texttemplate.New("requestLog").Parse(oc.RequestLogTemplate); err != nil {
			return nil, err
		}
	}

	return oc, nil
}

// ConfigMapName gets the name of the metrics ConfigMap
func ConfigMapName() string {
	if cm := os.Getenv(configMapNameEnv); cm != "" {
		return cm
	}
	return "config-observability"
}
<commit_msg>Fix comment on constant (#1973)<commit_after>/*
Copyright 2019 The Knative 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 metrics

import (
	"fmt"
	"os"
	texttemplate "text/template"

	corev1 "k8s.io/api/core/v1"
	cm "knative.dev/pkg/configmap"
)

const (
	// DefaultLogURLTemplate is used to set the default log url template
	DefaultLogURLTemplate = ""

	// DefaultRequestLogTemplate is the default format for emitting request logs.
	DefaultRequestLogTemplate = `{"httpRequest": {"requestMethod": "{{.Request.Method}}", "requestUrl": "{{js .Request.RequestURI}}", "requestSize": "{{.Request.ContentLength}}", "status": {{.Response.Code}}, "responseSize": "{{.Response.Size}}", "userAgent": "{{js .Request.UserAgent}}", "remoteIp": "{{js .Request.RemoteAddr}}", "serverIp": "{{.Revision.PodIP}}", "referer": "{{js .Request.Referer}}", "latency": "{{.Response.Latency}}s", "protocol": "{{.Request.Proto}}"}, "traceId": "{{index .Request.Header "X-B3-Traceid"}}"}`

	// The following is used to set the default metrics backend
	defaultRequestMetricsBackend = "prometheus"

	// The env var name for config-observability
	configMapNameEnv = "CONFIG_OBSERVABILITY_NAME"

	// ReqLogTemplateKey is the CM key for the request log template.
	ReqLogTemplateKey = "logging.request-log-template"

	// EnableReqLogKey is the CM key to enable request log.
	EnableReqLogKey = "logging.enable-request-log"

	// EnableProbeReqLogKey is the CM key to enable request logs for probe requests.
	EnableProbeReqLogKey = "logging.enable-probe-request-log"
)

// ObservabilityConfig contains the configuration defined in the observability ConfigMap.
// +k8s:deepcopy-gen=true
type ObservabilityConfig struct {
	// EnableVarLogCollection specifies whether the logs under /var/log/ should be available
	// for collection on the host node by the fluentd daemon set.
	EnableVarLogCollection bool

	// LoggingURLTemplate is a string containing the logging url template where
	// the variable REVISION_UID will be replaced with the created revision's UID.
	LoggingURLTemplate string

	// RequestLogTemplate is the go template to use to shape the request logs.
	RequestLogTemplate string

	// EnableProbeRequestLog enables queue-proxy to write health check probe request logs.
	EnableProbeRequestLog bool

	// RequestMetricsBackend specifies the request metrics destination, e.g. Prometheus,
	// Stackdriver. "None" disables all backends.
	RequestMetricsBackend string

	// EnableProfiling indicates whether it is allowed to retrieve runtime profiling data from
	// the pods via an HTTP server in the format expected by the pprof visualization tool.
	EnableProfiling bool

	// EnableRequestLog enables activator/queue-proxy to write request logs.
	EnableRequestLog bool

	// MetricsCollectorAddress specifies the metrics collector address. This is only used
	// when the metrics backend is opencensus.
	MetricsCollectorAddress string
}

func defaultConfig() *ObservabilityConfig {
	return &ObservabilityConfig{
		LoggingURLTemplate:    DefaultLogURLTemplate,
		RequestLogTemplate:    DefaultRequestLogTemplate,
		RequestMetricsBackend: defaultRequestMetricsBackend,
	}
}

// NewObservabilityConfigFromConfigMap creates a ObservabilityConfig from the supplied ConfigMap
func NewObservabilityConfigFromConfigMap(configMap *corev1.ConfigMap) (*ObservabilityConfig, error) {
	oc := defaultConfig()

	if err := cm.Parse(configMap.Data,
		cm.AsBool("logging.enable-var-log-collection", &oc.EnableVarLogCollection),
		cm.AsString("logging.revision-url-template", &oc.LoggingURLTemplate),
		cm.AsString(ReqLogTemplateKey, &oc.RequestLogTemplate),
		cm.AsBool(EnableReqLogKey, &oc.EnableRequestLog),
		cm.AsBool(EnableProbeReqLogKey, &oc.EnableProbeRequestLog),
		cm.AsString("metrics.request-metrics-backend-destination", &oc.RequestMetricsBackend),
		cm.AsBool("profiling.enable", &oc.EnableProfiling),
		cm.AsString("metrics.opencensus-address", &oc.MetricsCollectorAddress),
	); err != nil {
		return nil, err
	}

	if oc.RequestLogTemplate == "" && oc.EnableRequestLog {
		return nil, fmt.Errorf("%q was set to true, but no %q was specified", EnableReqLogKey, ReqLogTemplateKey)
	}

	if oc.RequestLogTemplate != "" {
		// Verify that we get valid templates.
		if _, err := texttemplate.New("requestLog").Parse(oc.RequestLogTemplate); err != nil {
			return nil, err
		}
	}

	return oc, nil
}

// ConfigMapName gets the name of the metrics ConfigMap
func ConfigMapName() string {
	if cm := os.Getenv(configMapNameEnv); cm != "" {
		return cm
	}
	return "config-observability"
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 config_test

import (
	"github.com/jacobsa/comeback/config"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestValidate(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type ValidateTest struct {
	cfg *config.Config
}

func init() { RegisterTestSuite(&ValidateTest{}) }

func (t *ValidateTest) SetUp(i *TestInfo) {
	t.cfg = &config.Config{Jobs: make(map[string]*config.Job)}
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *ValidateTest) JobNameNotValidUtf8() {
	t.cfg.Jobs["taco"] = &config.Job{BasePath: "/a"}
	t.cfg.Jobs["foo\x80\x81\x82bar"] = &config.Job{BasePath: "/b"}
	t.cfg.Jobs["burrito"] = &config.Job{BasePath: "/c"}

	err := config.Validate(t.cfg)

	ExpectThat(err, HasSubstr("name"))
	ExpectThat(err, HasSubstr("UTF-8"))
}

func (t *ValidateTest) EmptyBasePath() {
	ExpectEq("TODO", "")
}

func (t *ValidateTest) BasePathNotAbsolute() {
	ExpectEq("TODO", "")
}

func (t *ValidateTest) BasePathNotValidUtf8() {
	ExpectEq("TODO", "")
}

func (t *ValidateTest) EverythingValid() {
	ExpectEq("TODO", "")
}
<commit_msg>ValidateTest.BasePathNotValidUtf8<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 config_test

import (
	"github.com/jacobsa/comeback/config"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestValidate(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type ValidateTest struct {
	cfg *config.Config
}

func init() { RegisterTestSuite(&ValidateTest{}) }

func (t *ValidateTest) SetUp(i *TestInfo) {
	t.cfg = &config.Config{Jobs: make(map[string]*config.Job)}
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *ValidateTest) JobNameNotValidUtf8() {
	t.cfg.Jobs["taco"] = &config.Job{BasePath: "/a"}
	t.cfg.Jobs["foo\x80\x81\x82bar"] = &config.Job{BasePath: "/b"}
	t.cfg.Jobs["burrito"] = &config.Job{BasePath: "/c"}

	err := config.Validate(t.cfg)

	ExpectThat(err, HasSubstr("name"))
	ExpectThat(err, HasSubstr("UTF-8"))
}

func (t *ValidateTest) EmptyBasePath() {
	t.cfg.Jobs["taco"] = &config.Job{BasePath: ""}
	t.cfg.Jobs["burrito"] = &config.Job{BasePath: "/c"}

	err := config.Validate(t.cfg)

	ExpectThat(err, HasSubstr("base path"))
	ExpectThat(err, HasSubstr("taco"))
}

func (t *ValidateTest) BasePathNotAbsolute() {
	t.cfg.Jobs["taco"] = &config.Job{BasePath: "a"}
	t.cfg.Jobs["burrito"] = &config.Job{BasePath: "/c"}

	err := config.Validate(t.cfg)

	ExpectThat(err, HasSubstr("path"))
	ExpectThat(err, HasSubstr("absolute"))
	ExpectThat(err, HasSubstr("taco"))
}

func (t *ValidateTest) BasePathNotValidUtf8() {
	t.cfg.Jobs["taco"] = &config.Job{BasePath: "/a/\x80\x81\x82"}
	t.cfg.Jobs["burrito"] = &config.Job{BasePath: "/c"}

	err := config.Validate(t.cfg)

	ExpectThat(err, HasSubstr("path"))
	ExpectThat(err, HasSubstr("UTF-8"))
	ExpectThat(err, HasSubstr("taco"))
}

func (t *ValidateTest) EverythingValid() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

// +build ignore

// This program can be used as go_android_GOARCH_exec by the Go tool.
// It executes binaries on an android device using adb.
package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"
)

func run(args ...string) (string, error) {
	if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
		args = append(strings.Split(flags, " "), args...)
	}
	buf := new(bytes.Buffer)
	cmd := exec.Command("adb", args...)
	cmd.Stdout = io.MultiWriter(os.Stdout, buf)
	// If the adb subprocess somehow hangs, go test will kill this wrapper
	// and wait for our os.Stderr (and os.Stdout) to close as a result.
	// However, if the os.Stderr (or os.Stdout) file descriptors are
	// passed on, the hanging adb subprocess will hold them open and
	// go test will hang forever.
	//
	// Avoid that by wrapping stderr, breaking the short circuit and
	// forcing cmd.Run to use another pipe and goroutine to pass
	// along stderr from adb.
	cmd.Stderr = struct{ io.Writer }{os.Stderr}
	log.Printf("adb %s", strings.Join(args, " "))
	err := cmd.Run()
	if err != nil {
		return "", fmt.Errorf("adb %s: %v", strings.Join(args, " "), err)
	}
	return buf.String(), nil
}

const (
	deviceRoot   = "/data/local/tmp/go_android_exec"
	deviceGoroot = deviceRoot + "/goroot"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("go_android_exec: ")
	exitCode, err := runMain()
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func runMain() (int, error) {
	// Concurrent use of adb is flaky, so serialize adb commands.
	// See https://github.com/golang/go/issues/23795 or
	// https://issuetracker.google.com/issues/73230216.
	lockPath := filepath.Join(os.TempDir(), "go_android_exec-adb-lock")
	lock, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		return 0, err
	}
	defer lock.Close()
	if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil {
		return 0, err
	}

	// In case we're booting a device or emulator alongside all.bash, wait for
	// it to be ready. adb wait-for-device is not enough, we have to
	// wait for sys.boot_completed.
	if _, err := run("wait-for-device", "exec-out", "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;"); err != nil {
		return 0, err
	}

	// Done once per make.bash.
	if err := adbCopyGoroot(); err != nil {
		return 0, err
	}

	// Prepare a temporary directory that will be cleaned up at the end.
	// Binary names can conflict.
	// E.g. template.test from the {html,text}/template packages.
	binName := filepath.Base(os.Args[1])
	deviceGotmp := fmt.Sprintf(deviceRoot+"/%s-%d", binName, os.Getpid())
	deviceGopath := deviceGotmp + "/gopath"
	defer run("exec-out", "rm", "-rf", deviceGotmp) // Clean up.

	// Determine the package by examining the current working
	// directory, which will look something like
	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
	// We extract everything after the $GOROOT or $GOPATH to run on the
	// same relative directory on the target device.
	subdir, inGoRoot, err := subdir()
	if err != nil {
		return 0, err
	}
	deviceCwd := filepath.Join(deviceGopath, subdir)
	if inGoRoot {
		deviceCwd = filepath.Join(deviceGoroot, subdir)
	} else {
		if _, err := run("exec-out", "mkdir", "-p", deviceCwd); err != nil {
			return 0, err
		}
		if err := adbCopyTree(deviceCwd, subdir); err != nil {
			return 0, err
		}

		// Copy .go files from the package.
		goFiles, err := filepath.Glob("*.go")
		if err != nil {
			return 0, err
		}
		if len(goFiles) > 0 {
			args := append(append([]string{"push"}, goFiles...), deviceCwd)
			if _, err := run(args...); err != nil {
				return 0, err
			}
		}
	}

	deviceBin := fmt.Sprintf("%s/%s", deviceGotmp, binName)
	if _, err := run("push", os.Args[1], deviceBin); err != nil {
		return 0, err
	}

	// Forward SIGQUIT from the go command to show backtraces from
	// the binary instead of from this wrapper.
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGQUIT)
	go func() {
		for range quit {
			// We don't have the PID of the running process; use the
			// binary name instead.
			run("exec-out", "killall -QUIT "+binName)
		}
	}()
	// In light of
	// https://code.google.com/p/android/issues/detail?id=3254
	// dont trust the exitcode of adb. Instead, append the exitcode to
	// the output and parse it from there.
	const exitstr = "exitcode="
	cmd := `export TMPDIR="` + deviceGotmp + `"` +
		`; export GOROOT="` + deviceGoroot + `"` +
		`; export GOPATH="` + deviceGopath + `"` +
		`; export CGO_ENABLED=0` +
		`; export GOPROXY=` + os.Getenv("GOPROXY") +
		`; export GOCACHE="` + deviceRoot + `/gocache"` +
		`; export PATH=$PATH:"` + deviceGoroot + `/bin"` +
		`; cd "` + deviceCwd + `"` +
		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
		"; echo -n " + exitstr + "$?"
	output, err := run("exec-out", cmd)
	signal.Reset(syscall.SIGQUIT)
	close(quit)
	if err != nil {
		return 0, err
	}

	exitIdx := strings.LastIndex(output, exitstr)
	if exitIdx == -1 {
		return 0, fmt.Errorf("no exit code: %q", output)
	}
	code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
	if err != nil {
		return 0, fmt.Errorf("bad exit code: %v", err)
	}
	return code, nil
}

// subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool, err error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", false, err
	}
	cwd, err = filepath.EvalSymlinks(cwd)
	if err != nil {
		return "", false, err
	}
	goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
	if err != nil {
		return "", false, err
	}
	if subdir, err := filepath.Rel(goroot, cwd); err == nil {
		if !strings.Contains(subdir, "..") {
			return subdir, true, nil
		}
	}

	for _, p := range filepath.SplitList(build.Default.GOPATH) {
		pabs, err := filepath.EvalSymlinks(p)
		if err != nil {
			return "", false, err
		}
		if subdir, err := filepath.Rel(pabs, cwd); err == nil {
			if !strings.Contains(subdir, "..") {
				return subdir, false, nil
			}
		}
	}
	return "", false, fmt.Errorf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
		cwd, runtime.GOROOT(), build.Default.GOPATH)
}

// adbCopyTree copies testdata, go.mod, go.sum files from subdir
// and from parent directories all the way up to the root of subdir.
// go.mod and go.sum files are needed for the go tool modules queries,
// and the testdata directories for tests.  It is common for tests to
// reach out into testdata from parent packages.
func adbCopyTree(deviceCwd, subdir string) error {
	dir := ""
	for {
		for _, path := range []string{"testdata", "go.mod", "go.sum"} {
			path := filepath.Join(dir, path)
			if _, err := os.Stat(path); err != nil {
				continue
			}
			devicePath := filepath.Join(deviceCwd, dir)
			if _, err := run("exec-out", "mkdir", "-p", devicePath); err != nil {
				return err
			}
			if _, err := run("push", path, devicePath); err != nil {
				return err
			}
		}
		if subdir == "." {
			break
		}
		subdir = filepath.Dir(subdir)
		dir = filepath.Join(dir, "..")
	}
	return nil
}

// adbCopyGoroot clears deviceRoot for previous versions of GOROOT, GOPATH
// and temporary data. Then, it copies relevant parts of GOROOT to the device,
// including the go tool built for android.
// A lock file ensures this only happens once, even with concurrent exec
// wrappers.
func adbCopyGoroot() error {
	// Also known by cmd/dist. The bootstrap command deletes the file.
	statPath := filepath.Join(os.TempDir(), "go_android_exec-adb-sync-status")
	stat, err := os.OpenFile(statPath, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	defer stat.Close()
	// Serialize check and copying.
	if err := syscall.Flock(int(stat.Fd()), syscall.LOCK_EX); err != nil {
		return err
	}
	s, err := ioutil.ReadAll(stat)
	if err != nil {
		return err
	}
	if string(s) == "done" {
		return nil
	}
	// Delete GOROOT, GOPATH and any leftover test data.
	if _, err := run("exec-out", "rm", "-rf", deviceRoot); err != nil {
		return err
	}
	deviceBin := filepath.Join(deviceGoroot, "bin")
	if _, err := run("exec-out", "mkdir", "-p", deviceBin); err != nil {
		return err
	}
	goroot := runtime.GOROOT()
	// Build go for android.
	goCmd := filepath.Join(goroot, "bin", "go")
	tmpGo, err := ioutil.TempFile("", "go_android_exec-cmd-go-*")
	if err != nil {
		return err
	}
	tmpGo.Close()
	defer os.Remove(tmpGo.Name())

	if out, err := exec.Command(goCmd, "build", "-o", tmpGo.Name(), "cmd/go").CombinedOutput(); err != nil {
		return fmt.Errorf("failed to build go tool for device: %s\n%v", out, err)
	}
	deviceGo := filepath.Join(deviceBin, "go")
	if _, err := run("push", tmpGo.Name(), deviceGo); err != nil {
		return err
	}
	for _, dir := range []string{"src", "test", "lib", "api"} {
		if _, err := run("push", filepath.Join(goroot, dir), filepath.Join(deviceGoroot)); err != nil {
			return err
		}
	}

	// Copy only the relevant from pkg.
	if _, err := run("exec-out", "mkdir", "-p", filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
		return err
	}
	if _, err := run("push", filepath.Join(goroot, "pkg", "include"), filepath.Join(deviceGoroot, "pkg")); err != nil {
		return err
	}
	runtimea, err := exec.Command(goCmd, "list", "-f", "{{.Target}}", "runtime").Output()
	pkgdir := filepath.Dir(string(runtimea))
	if pkgdir == "" {
		return errors.New("could not find android pkg dir")
	}
	if _, err := run("push", pkgdir, filepath.Join(deviceGoroot, "pkg")); err != nil {
		return err
	}
	tooldir := filepath.Join(goroot, "pkg", "tool", filepath.Base(pkgdir))
	if _, err := run("push", tooldir, filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
		return err
	}

	if _, err := stat.Write([]byte("done")); err != nil {
		return err
	}
	return nil
}
<commit_msg>misc/android: silence adb output unless an error occurs<commit_after>// Copyright 2014 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.

// +build ignore

// This program can be used as go_android_GOARCH_exec by the Go tool.
// It executes binaries on an android device using adb.
package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"
)

func run(args ...string) (string, error) {
	cmd := adbCmd(args...)
	buf := new(bytes.Buffer)
	cmd.Stdout = io.MultiWriter(os.Stdout, buf)
	// If the adb subprocess somehow hangs, go test will kill this wrapper
	// and wait for our os.Stderr (and os.Stdout) to close as a result.
	// However, if the os.Stderr (or os.Stdout) file descriptors are
	// passed on, the hanging adb subprocess will hold them open and
	// go test will hang forever.
	//
	// Avoid that by wrapping stderr, breaking the short circuit and
	// forcing cmd.Run to use another pipe and goroutine to pass
	// along stderr from adb.
	cmd.Stderr = struct{ io.Writer }{os.Stderr}
	err := cmd.Run()
	if err != nil {
		return "", fmt.Errorf("adb %s: %v", strings.Join(args, " "), err)
	}
	return buf.String(), nil
}

func adb(args ...string) error {
	if out, err := adbCmd(args...).CombinedOutput(); err != nil {
		fmt.Fprintf(os.Stderr, "adb %s\n%s", strings.Join(args, " "), out)
		return err
	}
	return nil
}

func adbCmd(args ...string) *exec.Cmd {
	if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
		args = append(strings.Split(flags, " "), args...)
	}
	return exec.Command("adb", args...)
}

const (
	deviceRoot   = "/data/local/tmp/go_android_exec"
	deviceGoroot = deviceRoot + "/goroot"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("go_android_exec: ")
	exitCode, err := runMain()
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func runMain() (int, error) {
	// Concurrent use of adb is flaky, so serialize adb commands.
	// See https://github.com/golang/go/issues/23795 or
	// https://issuetracker.google.com/issues/73230216.
	lockPath := filepath.Join(os.TempDir(), "go_android_exec-adb-lock")
	lock, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		return 0, err
	}
	defer lock.Close()
	if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil {
		return 0, err
	}

	// In case we're booting a device or emulator alongside all.bash, wait for
	// it to be ready. adb wait-for-device is not enough, we have to
	// wait for sys.boot_completed.
	if err := adb("wait-for-device", "exec-out", "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;"); err != nil {
		return 0, err
	}

	// Done once per make.bash.
	if err := adbCopyGoroot(); err != nil {
		return 0, err
	}

	// Prepare a temporary directory that will be cleaned up at the end.
	// Binary names can conflict.
	// E.g. template.test from the {html,text}/template packages.
	binName := filepath.Base(os.Args[1])
	deviceGotmp := fmt.Sprintf(deviceRoot+"/%s-%d", binName, os.Getpid())
	deviceGopath := deviceGotmp + "/gopath"
	defer adb("exec-out", "rm", "-rf", deviceGotmp) // Clean up.

	// Determine the package by examining the current working
	// directory, which will look something like
	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
	// We extract everything after the $GOROOT or $GOPATH to run on the
	// same relative directory on the target device.
	subdir, inGoRoot, err := subdir()
	if err != nil {
		return 0, err
	}
	deviceCwd := filepath.Join(deviceGopath, subdir)
	if inGoRoot {
		deviceCwd = filepath.Join(deviceGoroot, subdir)
	} else {
		if err := adb("exec-out", "mkdir", "-p", deviceCwd); err != nil {
			return 0, err
		}
		if err := adbCopyTree(deviceCwd, subdir); err != nil {
			return 0, err
		}

		// Copy .go files from the package.
		goFiles, err := filepath.Glob("*.go")
		if err != nil {
			return 0, err
		}
		if len(goFiles) > 0 {
			args := append(append([]string{"push"}, goFiles...), deviceCwd)
			if err := adb(args...); err != nil {
				return 0, err
			}
		}
	}

	deviceBin := fmt.Sprintf("%s/%s", deviceGotmp, binName)
	if err := adb("push", os.Args[1], deviceBin); err != nil {
		return 0, err
	}

	// Forward SIGQUIT from the go command to show backtraces from
	// the binary instead of from this wrapper.
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGQUIT)
	go func() {
		for range quit {
			// We don't have the PID of the running process; use the
			// binary name instead.
			adb("exec-out", "killall -QUIT "+binName)
		}
	}()
	// In light of
	// https://code.google.com/p/android/issues/detail?id=3254
	// dont trust the exitcode of adb. Instead, append the exitcode to
	// the output and parse it from there.
	const exitstr = "exitcode="
	cmd := `export TMPDIR="` + deviceGotmp + `"` +
		`; export GOROOT="` + deviceGoroot + `"` +
		`; export GOPATH="` + deviceGopath + `"` +
		`; export CGO_ENABLED=0` +
		`; export GOPROXY=` + os.Getenv("GOPROXY") +
		`; export GOCACHE="` + deviceRoot + `/gocache"` +
		`; export PATH=$PATH:"` + deviceGoroot + `/bin"` +
		`; cd "` + deviceCwd + `"` +
		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
		"; echo -n " + exitstr + "$?"
	output, err := run("exec-out", cmd)
	signal.Reset(syscall.SIGQUIT)
	close(quit)
	if err != nil {
		return 0, err
	}

	exitIdx := strings.LastIndex(output, exitstr)
	if exitIdx == -1 {
		return 0, fmt.Errorf("no exit code: %q", output)
	}
	code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
	if err != nil {
		return 0, fmt.Errorf("bad exit code: %v", err)
	}
	return code, nil
}

// subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool, err error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", false, err
	}
	cwd, err = filepath.EvalSymlinks(cwd)
	if err != nil {
		return "", false, err
	}
	goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
	if err != nil {
		return "", false, err
	}
	if subdir, err := filepath.Rel(goroot, cwd); err == nil {
		if !strings.Contains(subdir, "..") {
			return subdir, true, nil
		}
	}

	for _, p := range filepath.SplitList(build.Default.GOPATH) {
		pabs, err := filepath.EvalSymlinks(p)
		if err != nil {
			return "", false, err
		}
		if subdir, err := filepath.Rel(pabs, cwd); err == nil {
			if !strings.Contains(subdir, "..") {
				return subdir, false, nil
			}
		}
	}
	return "", false, fmt.Errorf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
		cwd, runtime.GOROOT(), build.Default.GOPATH)
}

// adbCopyTree copies testdata, go.mod, go.sum files from subdir
// and from parent directories all the way up to the root of subdir.
// go.mod and go.sum files are needed for the go tool modules queries,
// and the testdata directories for tests.  It is common for tests to
// reach out into testdata from parent packages.
func adbCopyTree(deviceCwd, subdir string) error {
	dir := ""
	for {
		for _, path := range []string{"testdata", "go.mod", "go.sum"} {
			path := filepath.Join(dir, path)
			if _, err := os.Stat(path); err != nil {
				continue
			}
			devicePath := filepath.Join(deviceCwd, dir)
			if err := adb("exec-out", "mkdir", "-p", devicePath); err != nil {
				return err
			}
			if err := adb("push", path, devicePath); err != nil {
				return err
			}
		}
		if subdir == "." {
			break
		}
		subdir = filepath.Dir(subdir)
		dir = filepath.Join(dir, "..")
	}
	return nil
}

// adbCopyGoroot clears deviceRoot for previous versions of GOROOT, GOPATH
// and temporary data. Then, it copies relevant parts of GOROOT to the device,
// including the go tool built for android.
// A lock file ensures this only happens once, even with concurrent exec
// wrappers.
func adbCopyGoroot() error {
	// Also known by cmd/dist. The bootstrap command deletes the file.
	statPath := filepath.Join(os.TempDir(), "go_android_exec-adb-sync-status")
	stat, err := os.OpenFile(statPath, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	defer stat.Close()
	// Serialize check and copying.
	if err := syscall.Flock(int(stat.Fd()), syscall.LOCK_EX); err != nil {
		return err
	}
	s, err := ioutil.ReadAll(stat)
	if err != nil {
		return err
	}
	if string(s) == "done" {
		return nil
	}
	// Delete GOROOT, GOPATH and any leftover test data.
	if err := adb("exec-out", "rm", "-rf", deviceRoot); err != nil {
		return err
	}
	deviceBin := filepath.Join(deviceGoroot, "bin")
	if err := adb("exec-out", "mkdir", "-p", deviceBin); err != nil {
		return err
	}
	goroot := runtime.GOROOT()
	// Build go for android.
	goCmd := filepath.Join(goroot, "bin", "go")
	tmpGo, err := ioutil.TempFile("", "go_android_exec-cmd-go-*")
	if err != nil {
		return err
	}
	tmpGo.Close()
	defer os.Remove(tmpGo.Name())

	if out, err := exec.Command(goCmd, "build", "-o", tmpGo.Name(), "cmd/go").CombinedOutput(); err != nil {
		return fmt.Errorf("failed to build go tool for device: %s\n%v", out, err)
	}
	deviceGo := filepath.Join(deviceBin, "go")
	if err := adb("push", tmpGo.Name(), deviceGo); err != nil {
		return err
	}
	for _, dir := range []string{"src", "test", "lib", "api"} {
		if err := adb("push", filepath.Join(goroot, dir), filepath.Join(deviceGoroot)); err != nil {
			return err
		}
	}

	// Copy only the relevant from pkg.
	if err := adb("exec-out", "mkdir", "-p", filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
		return err
	}
	if err := adb("push", filepath.Join(goroot, "pkg", "include"), filepath.Join(deviceGoroot, "pkg")); err != nil {
		return err
	}
	runtimea, err := exec.Command(goCmd, "list", "-f", "{{.Target}}", "runtime").Output()
	pkgdir := filepath.Dir(string(runtimea))
	if pkgdir == "" {
		return errors.New("could not find android pkg dir")
	}
	if err := adb("push", pkgdir, filepath.Join(deviceGoroot, "pkg")); err != nil {
		return err
	}
	tooldir := filepath.Join(goroot, "pkg", "tool", filepath.Base(pkgdir))
	if err := adb("push", tooldir, filepath.Join(deviceGoroot, "pkg", "tool")); err != nil {
		return err
	}

	if _, err := stat.Write([]byte("done")); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package pdb

import (
	"fmt"

	"github.com/BurntSushi/bcbgo/seq"
)

type Entry struct {
	Path   string
	IdCode string
	Chains []*Chain
}

type Chain struct {
	Entry    *Entry
	Ident    byte
	SeqType  SequenceType
	Sequence []seq.Residue
	Models   []*Model
	Missing  []*Residue
}

type Model struct {
	Entry    *Entry
	Chain    *Chain
	Num      int
	Residues []*Residue
}

type Residue struct {
	Name          seq.Residue
	SequenceNum   int
	InsertionCode byte
	Atoms         []Atom
}

type Atom struct {
	Name string
	Het  bool
	Coords
}

type Coords struct {
	X, Y, Z float64
}

// Chain returns a chain with the given identifier.
// If such a chain does not exist, nil is returned.
func (entry *Entry) Chain(ident byte) *Chain {
	for i := range entry.Chains {
		if entry.Chains[i].Ident == ident {
			return entry.Chains[i]
		}
	}
	return nil
}

// OneChain returns a single chain in the PDB file. If there is more than one
// chain, OneChain will panic. This is convenient when you expect a PDB file to
// have only a single chain, but don't know the name.
func (entry *Entry) OneChain() *Chain {
	if len(entry.Chains) != 1 {
		panic(fmt.Sprintf("OneChain can only be called on PDB entries with "+
			"ONE chain. But the '%s' PDB entry has %d chains.",
			entry.Path, len(entry.Chains)))
	}
	return entry.Chains[0]
}

// IsProtein returns true if the chain consists of amino acids.
func (c Chain) IsProtein() bool {
	return c.SeqType == SeqProtein
}

// SequenceCaAtomSlice attempts to extract a contiguous slice of alpha-carbon
// ATOM records based on *residue* index. Namely, if a contiguous slice cannot
// be found, nil is returned. If there is more than one model, the first model
// is used.
func (c Chain) SequenceCaAtomSlice(start, end int) []Coords {
	return c.Models[0].SequenceCaAtomSlice(start, end)
}

// SequenceCaAtoms returns a slice of all Ca atoms for the chain in
// correspondence with the sequence in SEQRES (automatically using the first
// model).
//
// See Model.SequenceCaAtoms for the deets.
func (c Chain) SequenceCaAtoms() ([]*Coords, error) {
	return c.Models[0].SequenceCaAtoms()
}

// SequenceAtoms returns a slice of all residues for the chain in
// correspondence with the sequence in SEQRES (automatically using the first
// model). Namely, the mapping is sparse, since not all SEQRES residues have
// an ATOM record.
//
// See Model.SequenceCaAtoms for the deets.
func (c Chain) SequenceAtoms() ([]*Residue, error) {
	return c.Models[0].SequenceAtoms()
}

// CaAtoms returns all alpha-carbon atoms in the chain. If there is more than
// one model, only the first model is used.
func (c Chain) CaAtoms() []Coords {
	return c.Models[0].CaAtoms()
}

// SequenceCaAtomSlice attempts to extract a contiguous slice of alpha-carbon
// ATOM records based on *residue* index. Namely, if a contiguous slice cannot
// be found, nil is returned.
func (m Model) SequenceCaAtomSlice(start, end int) []Coords {
	residues, err := m.SequenceCaAtoms()
	if err != nil {
		return nil
	}

	atoms := make([]Coords, end-start)
	for i, cai := 0, start; cai < end; i, cai = i+1, cai+1 {
		if residues[start] == nil {
			return nil
		}
		atoms[i] = *residues[cai]
	}
	return atoms
}

// SequenceCaAtoms returns a slice of all Ca atoms for the model in
// correspondence with the sequence in SEQRES.
// Note that a slice of pointers is returned, since not all residues
// necessarily correspond to a alpha-carbon ATOM.
//
// This method can proceed in one of two ways. First, if "REMARK 465" is
// present in the PDB file, it will be used to determine the positions of the
// holes in the sequence (i.e., residues in SEQRES without an ATOM record).
// This method is generally reliable, since REMARK 465 lists all residues
// in SEQRES that don't have an ATOM record. This will fail if there are any
// unreported missing residues.
//
// If "REMARK 465" is absent, then we have to rely on the order of ATOM records
// to correspond to a residue index in the SEQRES sequence. This will fail
// with an error if there are any unreported missing residues.
//
// Generally, false positives are limited by returning errors if corruption
// is detected. However, false positives can be returned in pathological cases
// (like long strings of low complexity regions or UNKNOWN amino acids), but
// they are rare. Probably on the order of a handful in the entire PDB.
//
// In sum, a list of atom pointers is returned with length equal to the number
// of residues in the SEQRES record for this model. Some pointers may be nil.
func (m Model) SequenceCaAtoms() ([]*Coords, error) {
	mapping, err := m.SequenceAtoms()
	if err != nil {
		return nil, err
	}

	cas := make([]*Coords, len(mapping))
	for i := range mapping {
		if mapping[i] != nil {
			cas[i] = mapping[i].Ca()
		}
	}
	return cas, nil
}

// SequenceAtoms is just like SequenceCaAtoms, except it returns the residues
// instead of the alpha-carbon coordinates directly. The advantage here is to
// get a mapping that isn't limited by the presence of alpha-carbon atoms.
//
// See SequenceCaAtoms for the deets.
func (m Model) SequenceAtoms() ([]*Residue, error) {
	if len(m.Chain.Missing) > 0 {
		return m.seqAtomsChunksMerge()
	}
	return m.seqAtomsGuess()
}

// CaAtoms returns all alpha-carbon atoms in the model.
// This includes multiple alpha-carbon atoms belonging to the same residue.
// It does not include HETATMs.
func (m Model) CaAtoms() []Coords {
	cas := make([]Coords, 0, len(m.Residues))
	for _, r := range m.Residues {
		for _, atom := range r.Atoms {
			if atom.Name == "CA" && !atom.Het {
				cas = append(cas, atom.Coords)
			}
		}
	}
	return cas
}

// Ca returns the alpha-carbon atom in this residue.
// If one does not exist, nil is returned.
func (r Residue) Ca() *Coords {
	for _, atom := range r.Atoms {
		if atom.Name == "CA" {
			return &atom.Coords
		}
	}
	return nil
}

func (coords Coords) String() string {
	return fmt.Sprintf("%0.3f %0.3f %0.3f", coords.X, coords.Y, coords.Z)
}
<commit_msg>re-ran fragbag-pride experiment. phew.<commit_after>package pdb

import (
	"fmt"

	"github.com/BurntSushi/bcbgo/seq"
)

type Entry struct {
	Path   string
	IdCode string
	Chains []*Chain
}

type Chain struct {
	Entry    *Entry
	Ident    byte
	SeqType  SequenceType
	Sequence []seq.Residue
	Models   []*Model
	Missing  []*Residue
}

type Model struct {
	Entry    *Entry
	Chain    *Chain
	Num      int
	Residues []*Residue
}

type Residue struct {
	Name          seq.Residue
	SequenceNum   int
	InsertionCode byte
	Atoms         []Atom
}

type Atom struct {
	Name string
	Het  bool
	Coords
}

type Coords struct {
	X, Y, Z float64
}

// Chain returns a chain with the given identifier.
// If such a chain does not exist, nil is returned.
func (entry *Entry) Chain(ident byte) *Chain {
	for i := range entry.Chains {
		if entry.Chains[i].Ident == ident {
			return entry.Chains[i]
		}
	}
	return nil
}

// OneChain returns a single chain in the PDB file. If there is more than one
// chain, OneChain will panic. This is convenient when you expect a PDB file to
// have only a single chain, but don't know the name.
func (entry *Entry) OneChain() *Chain {
	if len(entry.Chains) != 1 {
		panic(fmt.Sprintf("OneChain can only be called on PDB entries with "+
			"ONE chain. But the '%s' PDB entry has %d chains.",
			entry.Path, len(entry.Chains)))
	}
	return entry.Chains[0]
}

// IsProtein returns true if the chain consists of amino acids.
func (c Chain) IsProtein() bool {
	return c.SeqType == SeqProtein && len(c.Models) > 0
}

// SequenceCaAtomSlice attempts to extract a contiguous slice of alpha-carbon
// ATOM records based on *residue* index. Namely, if a contiguous slice cannot
// be found, nil is returned. If there is more than one model, the first model
// is used.
func (c Chain) SequenceCaAtomSlice(start, end int) []Coords {
	return c.Models[0].SequenceCaAtomSlice(start, end)
}

// SequenceCaAtoms returns a slice of all Ca atoms for the chain in
// correspondence with the sequence in SEQRES (automatically using the first
// model).
//
// See Model.SequenceCaAtoms for the deets.
func (c Chain) SequenceCaAtoms() ([]*Coords, error) {
	return c.Models[0].SequenceCaAtoms()
}

// SequenceAtoms returns a slice of all residues for the chain in
// correspondence with the sequence in SEQRES (automatically using the first
// model). Namely, the mapping is sparse, since not all SEQRES residues have
// an ATOM record.
//
// See Model.SequenceCaAtoms for the deets.
func (c Chain) SequenceAtoms() ([]*Residue, error) {
	return c.Models[0].SequenceAtoms()
}

// CaAtoms returns all alpha-carbon atoms in the chain. If there is more than
// one model, only the first model is used.
func (c Chain) CaAtoms() []Coords {
	return c.Models[0].CaAtoms()
}

// SequenceCaAtomSlice attempts to extract a contiguous slice of alpha-carbon
// ATOM records based on *residue* index. Namely, if a contiguous slice cannot
// be found, nil is returned.
func (m Model) SequenceCaAtomSlice(start, end int) []Coords {
	residues, err := m.SequenceCaAtoms()
	if err != nil {
		return nil
	}

	atoms := make([]Coords, end-start)
	for i, cai := 0, start; cai < end; i, cai = i+1, cai+1 {
		if residues[start] == nil {
			return nil
		}
		atoms[i] = *residues[cai]
	}
	return atoms
}

// SequenceCaAtoms returns a slice of all Ca atoms for the model in
// correspondence with the sequence in SEQRES.
// Note that a slice of pointers is returned, since not all residues
// necessarily correspond to a alpha-carbon ATOM.
//
// This method can proceed in one of two ways. First, if "REMARK 465" is
// present in the PDB file, it will be used to determine the positions of the
// holes in the sequence (i.e., residues in SEQRES without an ATOM record).
// This method is generally reliable, since REMARK 465 lists all residues
// in SEQRES that don't have an ATOM record. This will fail if there are any
// unreported missing residues.
//
// If "REMARK 465" is absent, then we have to rely on the order of ATOM records
// to correspond to a residue index in the SEQRES sequence. This will fail
// with an error if there are any unreported missing residues.
//
// Generally, false positives are limited by returning errors if corruption
// is detected. However, false positives can be returned in pathological cases
// (like long strings of low complexity regions or UNKNOWN amino acids), but
// they are rare. Probably on the order of a handful in the entire PDB.
//
// In sum, a list of atom pointers is returned with length equal to the number
// of residues in the SEQRES record for this model. Some pointers may be nil.
func (m Model) SequenceCaAtoms() ([]*Coords, error) {
	mapping, err := m.SequenceAtoms()
	if err != nil {
		return nil, err
	}

	cas := make([]*Coords, len(mapping))
	for i := range mapping {
		if mapping[i] != nil {
			cas[i] = mapping[i].Ca()
		}
	}
	return cas, nil
}

// SequenceAtoms is just like SequenceCaAtoms, except it returns the residues
// instead of the alpha-carbon coordinates directly. The advantage here is to
// get a mapping that isn't limited by the presence of alpha-carbon atoms.
//
// See SequenceCaAtoms for the deets.
func (m Model) SequenceAtoms() ([]*Residue, error) {
	if len(m.Chain.Missing) > 0 {
		return m.seqAtomsChunksMerge()
	}
	return m.seqAtomsGuess()
}

// CaAtoms returns all alpha-carbon atoms in the model.
// This includes multiple alpha-carbon atoms belonging to the same residue.
// It does not include HETATMs.
func (m Model) CaAtoms() []Coords {
	cas := make([]Coords, 0, len(m.Residues))
	for _, r := range m.Residues {
		for _, atom := range r.Atoms {
			if atom.Name == "CA" && !atom.Het {
				cas = append(cas, atom.Coords)
			}
		}
	}
	return cas
}

// Ca returns the alpha-carbon atom in this residue.
// If one does not exist, nil is returned.
func (r Residue) Ca() *Coords {
	for _, atom := range r.Atoms {
		if atom.Name == "CA" {
			return &atom.Coords
		}
	}
	return nil
}

func (coords Coords) String() string {
	return fmt.Sprintf("%0.3f %0.3f %0.3f", coords.X, coords.Y, coords.Z)
}
<|endoftext|>


<commit_before>package peco

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/peco/peco/internal/util"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type interceptorArgs []interface{}
type interceptor struct {
	m      sync.Mutex
	events map[string][]interceptorArgs
}

func newInterceptor() *interceptor {
	return &interceptor{
		events: make(map[string][]interceptorArgs),
	}
}

func (i *interceptor) reset() {
	i.m.Lock()
	defer i.m.Unlock()

	i.events = make(map[string][]interceptorArgs)
}

func (i *interceptor) record(name string, args []interface{}) {
	i.m.Lock()
	defer i.m.Unlock()

	events := i.events
	v, ok := events[name]
	if !ok {
		v = []interceptorArgs{}
	}

	events[name] = append(v, interceptorArgs(args))
}

func newPeco() *Peco {
	_, file, _, _ := runtime.Caller(0)
	state := New()
	state.Argv = []string{"peco", file}
	state.screen = NewDummyScreen()
	return state
}

type dummyScreen struct {
	*interceptor
	width  int
	height int
	pollCh chan termbox.Event
}

func NewDummyScreen() *dummyScreen {
	return &dummyScreen{
		interceptor: newInterceptor(),
		width:       80,
		height:      10,
		pollCh:      make(chan termbox.Event),
	}
}

func (d dummyScreen) Init() error {
	return nil
}

func (d dummyScreen) Close() error {
	return nil
}

func (d dummyScreen) Print(args PrintArgs) int {
	return screenPrint(d, args)
}

func (d dummyScreen) SendEvent(e termbox.Event) {
	d.pollCh <- e
}

func (d dummyScreen) SetCell(x, y int, ch rune, fg, bg termbox.Attribute) {
	d.record("SetCell", interceptorArgs{x, y, ch, fg, bg})
}
func (d dummyScreen) Flush() error {
	d.record("Flush", interceptorArgs{})
	return nil
}
func (d dummyScreen) PollEvent() chan termbox.Event {
	return d.pollCh
}
func (d dummyScreen) Size() (int, int) {
	return d.width, d.height
}

func TestIDGen(t *testing.T) {
	idgen := newIDGen()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go idgen.Run(ctx)

	lines := []*RawLine{}
	for i := 0; i < 1000000; i++ {
		lines = append(lines, NewRawLine(idgen.next(), fmt.Sprintf("%d", i), false))
	}

	sel := NewSelection()
	for _, l := range lines {
		if sel.Has(l) {
			t.Errorf("Collision detected %d", l.ID())
		}
		sel.Add(l)
	}
}

func TestPeco(t *testing.T) {
	p := newPeco()
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)
	if !assert.NoError(t, p.Run(ctx), "p.Run() succeeds") {
		return
	}
}

type testCauser interface {
	Cause() error
}
type testIgnorableError interface {
	Ignorable() bool
}

func TestPecoHelp(t *testing.T) {
	p := newPeco()
	p.Argv = []string{"peco", "-h"}
	p.Stdout = &bytes.Buffer{}
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	err := p.Run(ctx)
	if !assert.True(t, util.IsIgnorableError(err), "p.Run() should return error with Ignorable() method, and it should return true") {
		return
	}
}

func TestGHIssue331(t *testing.T) {
	// Note: we should check that the drawing process did not
	// use cached display, but ATM this seemed hard to do,
	// so we just check that the proper fields were populated
	// when peco was instantiated
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	p := newPeco()
	p.Run(ctx)

	if !assert.NotEmpty(t, p.singleKeyJumpPrefixes, "singleKeyJumpPrefixes is not empty") {
		return
	}
	if !assert.NotEmpty(t, p.singleKeyJumpPrefixMap, "singleKeyJumpPrefixMap is not empty") {
		return
	}
}
<commit_msg>Add a test for this<commit_after>package peco

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/peco/peco/internal/util"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

type interceptorArgs []interface{}
type interceptor struct {
	m      sync.Mutex
	events map[string][]interceptorArgs
}

func newInterceptor() *interceptor {
	return &interceptor{
		events: make(map[string][]interceptorArgs),
	}
}

func (i *interceptor) reset() {
	i.m.Lock()
	defer i.m.Unlock()

	i.events = make(map[string][]interceptorArgs)
}

func (i *interceptor) record(name string, args []interface{}) {
	i.m.Lock()
	defer i.m.Unlock()

	events := i.events
	v, ok := events[name]
	if !ok {
		v = []interceptorArgs{}
	}

	events[name] = append(v, interceptorArgs(args))
}

func newPeco() *Peco {
	_, file, _, _ := runtime.Caller(0)
	state := New()
	state.Argv = []string{"peco", file}
	state.screen = NewDummyScreen()
	return state
}

type dummyScreen struct {
	*interceptor
	width  int
	height int
	pollCh chan termbox.Event
}

func NewDummyScreen() *dummyScreen {
	return &dummyScreen{
		interceptor: newInterceptor(),
		width:       80,
		height:      10,
		pollCh:      make(chan termbox.Event),
	}
}

func (d dummyScreen) Init() error {
	return nil
}

func (d dummyScreen) Close() error {
	return nil
}

func (d dummyScreen) Print(args PrintArgs) int {
	return screenPrint(d, args)
}

func (d dummyScreen) SendEvent(e termbox.Event) {
	d.pollCh <- e
}

func (d dummyScreen) SetCell(x, y int, ch rune, fg, bg termbox.Attribute) {
	d.record("SetCell", interceptorArgs{x, y, ch, fg, bg})
}
func (d dummyScreen) Flush() error {
	d.record("Flush", interceptorArgs{})
	return nil
}
func (d dummyScreen) PollEvent() chan termbox.Event {
	return d.pollCh
}
func (d dummyScreen) Size() (int, int) {
	return d.width, d.height
}

func TestIDGen(t *testing.T) {
	idgen := newIDGen()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go idgen.Run(ctx)

	lines := []*RawLine{}
	for i := 0; i < 1000000; i++ {
		lines = append(lines, NewRawLine(idgen.next(), fmt.Sprintf("%d", i), false))
	}

	sel := NewSelection()
	for _, l := range lines {
		if sel.Has(l) {
			t.Errorf("Collision detected %d", l.ID())
		}
		sel.Add(l)
	}
}

func TestPeco(t *testing.T) {
	p := newPeco()
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)
	if !assert.NoError(t, p.Run(ctx), "p.Run() succeeds") {
		return
	}
}

type testCauser interface {
	Cause() error
}
type testIgnorableError interface {
	Ignorable() bool
}

func TestPecoHelp(t *testing.T) {
	p := newPeco()
	p.Argv = []string{"peco", "-h"}
	p.Stdout = &bytes.Buffer{}
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	err := p.Run(ctx)
	if !assert.True(t, util.IsIgnorableError(err), "p.Run() should return error with Ignorable() method, and it should return true") {
		return
	}
}

func TestGHIssue331(t *testing.T) {
	// Note: we should check that the drawing process did not
	// use cached display, but ATM this seemed hard to do,
	// so we just check that the proper fields were populated
	// when peco was instantiated
	ctx, cancel := context.WithCancel(context.Background())
	time.AfterFunc(time.Second, cancel)

	p := newPeco()
	p.Run(ctx)

	if !assert.NotEmpty(t, p.singleKeyJumpPrefixes, "singleKeyJumpPrefixes is not empty") {
		return
	}
	if !assert.NotEmpty(t, p.singleKeyJumpPrefixMap, "singleKeyJumpPrefixMap is not empty") {
		return
	}
}

func TestApplyConfig(t *testing.T) {
	// XXX We should add all the possible configurations that needs to be
	// propagated to Peco from config

	// This is a placeholder test address
	// https://github.com/peco/peco/pull/338#issuecomment-244462220
	var opts CLIOptions

	opts.OptPrompt = "tpmorp>"
	p := newPeco()
	if !assert.NoError(t, p.ApplyConfig(opts), "p.ApplyConfig should succeed") {
		return
	}

	if !assert.Equal(t, opts.OptPrompt, p.prompt, "p.Prompt should be equal to opts.PRompt") {
		return
	}
}
<|endoftext|>


<commit_before>package peer

import (
	"bytes"
	"errors"
	"fmt"
	"sync"
	"time"

	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"

	ic "github.com/jbenet/go-ipfs/crypto"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("peer")

// ID is a byte slice representing the identity of a peer.
type ID mh.Multihash

// String is utililty function for printing out peer ID strings.
func (id ID) String() string {
	return id.Pretty()
}

// Equal is utililty function for comparing two peer ID's
func (id ID) Equal(other ID) bool {
	return bytes.Equal(id, other)
}

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return b58.Encode(id)
}

// DecodePrettyID returns a b58-encoded string of the ID
func DecodePrettyID(s string) ID {
	return b58.Decode(s)
}

// IDFromPubKey retrieves a Public Key from the peer given by pk
func IDFromPubKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// Map maps Key (string) : *peer (slices are not comparable).
type Map map[u.Key]Peer

// Peer represents the identity information of an IPFS Node, including
// ID, and relevant Addresses.
type Peer interface {
	// ID returns the peer's ID
	ID() ID

	// Key returns the ID as a Key (string) for maps.
	Key() u.Key

	// Addresses returns the peer's multiaddrs
	Addresses() []ma.Multiaddr

	// AddAddress adds the given Multiaddr address to Peer's addresses.
	// returns whether this was a newly added address.
	AddAddress(a ma.Multiaddr) bool

	// NetAddress returns the first Multiaddr found for a given network.
	NetAddress(n string) ma.Multiaddr

	// Services returns the peer's services
	// Services() []mux.ProtocolID
	// SetServices([]mux.ProtocolID)

	// Priv/PubKey returns the peer's Private Key
	PrivKey() ic.PrivKey
	PubKey() ic.PubKey

	// LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
	// Error if (a) unmarshalling fails, or (b) pubkey does not match id.
	LoadAndVerifyKeyPair(marshalled []byte) error
	VerifyAndSetPrivKey(sk ic.PrivKey) error
	VerifyAndSetPubKey(pk ic.PubKey) error

	// Get/SetLatency manipulate the current latency measurement.
	GetLatency() (out time.Duration)
	SetLatency(laten time.Duration)

	// Update with the data of another peer instance
	Update(Peer) error
}

type peer struct {
	id        ID
	addresses []ma.Multiaddr
	// services  []mux.ProtocolID

	privKey ic.PrivKey
	pubKey  ic.PubKey

	latency time.Duration

	sync.RWMutex
}

// String prints out the peer.
func (p *peer) String() string {
	return "[Peer " + p.id.String()[:12] + "]"
}

// Key returns the ID as a Key (string) for maps.
func (p *peer) Key() u.Key {
	return u.Key(p.id)
}

// ID returns the peer's ID
func (p *peer) ID() ID {
	return p.id
}

// PrivKey returns the peer's Private Key
func (p *peer) PrivKey() ic.PrivKey {
	return p.privKey
}

// PubKey returns the peer's Private Key
func (p *peer) PubKey() ic.PubKey {
	return p.pubKey
}

// Addresses returns the peer's multiaddrs
func (p *peer) Addresses() []ma.Multiaddr {
	cp := make([]ma.Multiaddr, len(p.addresses))
	p.RLock()
	copy(cp, p.addresses)
	defer p.RUnlock()
	return cp
}

// AddAddress adds the given Multiaddr address to Peer's addresses.
// Returns whether this address was a newly added address
func (p *peer) AddAddress(a ma.Multiaddr) bool {
	p.Lock()
	defer p.Unlock()

	for _, addr := range p.addresses {
		if addr.Equal(a) {
			return false
		}
	}
	p.addresses = append(p.addresses, a)
	return true
}

// NetAddress returns the first Multiaddr found for a given network.
func (p *peer) NetAddress(n string) ma.Multiaddr {
	p.RLock()
	defer p.RUnlock()

	for _, a := range p.addresses {
		for _, p := range a.Protocols() {
			if p.Name == n {
				return a
			}
		}
	}
	return nil
}

// func (p *peer) Services() []mux.ProtocolID {
// 	p.RLock()
// 	defer p.RUnlock()
// 	return p.services
// }
//
// func (p *peer) SetServices(s []mux.ProtocolID) {
// 	p.Lock()
// 	defer p.Unlock()
// 	p.services = s
// }

// GetLatency retrieves the current latency measurement.
func (p *peer) GetLatency() (out time.Duration) {
	p.RLock()
	out = p.latency
	p.RUnlock()
	return
}

// SetLatency sets the latency measurement.
// TODO: Instead of just keeping a single number,
//		 keep a running average over the last hour or so
// Yep, should be EWMA or something. (-jbenet)
func (p *peer) SetLatency(laten time.Duration) {
	p.Lock()
	if p.latency == 0 {
		p.latency = laten
	} else {
		p.latency = ((p.latency * 9) + laten) / 10
	}
	p.Unlock()
}

// LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
// Error if (a) unmarshalling fails, or (b) pubkey does not match id.
func (p *peer) LoadAndVerifyKeyPair(marshalled []byte) error {
	sk, err := ic.UnmarshalPrivateKey(marshalled)
	if err != nil {
		return fmt.Errorf("Failed to unmarshal private key: %v", err)
	}

	return p.VerifyAndSetPrivKey(sk)
}

// VerifyAndSetPrivKey sets private key, given its pubkey matches the peer.ID
func (p *peer) VerifyAndSetPrivKey(sk ic.PrivKey) error {

	// construct and assign pubkey. ensure it matches this peer
	if err := p.VerifyAndSetPubKey(sk.GetPublic()); err != nil {
		return err
	}

	p.Lock()
	defer p.Unlock()

	// if we didn't have the priavte key, assign it
	if p.privKey == nil {
		p.privKey = sk
		return nil
	}

	// if we already had the keys, check they're equal.
	if p.privKey.Equals(sk) {
		return nil // as expected. keep the old objects.
	}

	// keys not equal. invariant violated. this warrants a panic.
	// these keys should be _the same_ because peer.ID = H(pk)
	// this mismatch should never happen.
	log.Errorf("%s had PrivKey: %v -- got %v", p, p.privKey, sk)
	panic("invariant violated: unexpected key mismatch")
}

// VerifyAndSetPubKey sets public key, given it matches the peer.ID
func (p *peer) VerifyAndSetPubKey(pk ic.PubKey) error {
	pkid, err := IDFromPubKey(pk)
	if err != nil {
		return fmt.Errorf("Failed to hash public key: %v", err)
	}

	p.Lock()
	defer p.Unlock()

	if !p.id.Equal(pkid) {
		return fmt.Errorf("Public key does not match peer.ID.")
	}

	// if we didn't have the keys, assign them.
	if p.pubKey == nil {
		p.pubKey = pk
		return nil
	}

	// if we already had the pubkey, check they're equal.
	if p.pubKey.Equals(pk) {
		return nil // as expected. keep the old objects.
	}

	// keys not equal. invariant violated. this warrants a panic.
	// these keys should be _the same_ because peer.ID = H(pk)
	// this mismatch should never happen.
	log.Errorf("%s had PubKey: %v -- got %v", p, p.pubKey, pk)
	panic("invariant violated: unexpected key mismatch")
}

// Updates this peer with information from another peer instance
func (p *peer) Update(other Peer) error {
	if !p.ID().Equal(other.ID()) {
		return errors.New("peer ids do not match")
	}

	for _, a := range other.Addresses() {
		p.AddAddress(a)
	}

	p.SetLatency(other.GetLatency())

	sk := other.PrivKey()
	pk := other.PubKey()
	p.Lock()
	if p.privKey == nil {
		p.privKey = sk
	}

	if p.pubKey == nil {
		p.pubKey = pk
	}
	defer p.Unlock()
	return nil
}

// WithKeyPair returns a Peer object with given keys.
func WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error) {
	if sk == nil && pk == nil {
		return nil, fmt.Errorf("PeerWithKeyPair nil keys")
	}

	pk2 := sk.GetPublic()
	if pk == nil {
		pk = pk2
	} else if !pk.Equals(pk2) {
		return nil, fmt.Errorf("key mismatch. pubkey is not privkey's pubkey")
	}

	pkid, err := IDFromPubKey(pk)
	if err != nil {
		return nil, fmt.Errorf("Failed to hash public key: %v", err)
	}

	return &peer{id: pkid, pubKey: pk, privKey: sk}, nil
}

// WithID constructs a peer with given ID.
func WithID(id ID) Peer {
	return &peer{id: id}
}

// WithIDString constructs a peer with given ID (string).
func WithIDString(id string) Peer {
	return WithID(ID(id))
}
<commit_msg>doc(peer)<commit_after>package peer

import (
	"bytes"
	"errors"
	"fmt"
	"sync"
	"time"

	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"

	ic "github.com/jbenet/go-ipfs/crypto"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("peer")

// ID is a byte slice representing the identity of a peer.
type ID mh.Multihash

// String is utililty function for printing out peer ID strings.
func (id ID) String() string {
	return id.Pretty()
}

// Equal is utililty function for comparing two peer ID's
func (id ID) Equal(other ID) bool {
	return bytes.Equal(id, other)
}

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return b58.Encode(id)
}

// DecodePrettyID returns a b58-encoded string of the ID
func DecodePrettyID(s string) ID {
	return b58.Decode(s)
}

// IDFromPubKey retrieves a Public Key from the peer given by pk
func IDFromPubKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return nil, err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// Map maps Key (string) : *peer (slices are not comparable).
type Map map[u.Key]Peer

// Peer represents the identity information of an IPFS Node, including
// ID, and relevant Addresses.
type Peer interface {

	// TODO reduce the peer interface to be read-only. Force mutations to occur
	// on the peer store eg. peerstore.SetLatency(peerId, value).

	// ID returns the peer's ID
	ID() ID

	// Key returns the ID as a Key (string) for maps.
	Key() u.Key

	// Addresses returns the peer's multiaddrs
	Addresses() []ma.Multiaddr

	// AddAddress adds the given Multiaddr address to Peer's addresses.
	// returns whether this was a newly added address.
	AddAddress(a ma.Multiaddr) bool

	// NetAddress returns the first Multiaddr found for a given network.
	NetAddress(n string) ma.Multiaddr

	// Services returns the peer's services
	// Services() []mux.ProtocolID
	// SetServices([]mux.ProtocolID)

	// Priv/PubKey returns the peer's Private Key
	PrivKey() ic.PrivKey
	PubKey() ic.PubKey

	// LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
	// Error if (a) unmarshalling fails, or (b) pubkey does not match id.
	LoadAndVerifyKeyPair(marshalled []byte) error
	VerifyAndSetPrivKey(sk ic.PrivKey) error
	VerifyAndSetPubKey(pk ic.PubKey) error

	// Get/SetLatency manipulate the current latency measurement.
	GetLatency() (out time.Duration)
	SetLatency(laten time.Duration)

	// Update with the data of another peer instance
	Update(Peer) error
}

type peer struct {
	id        ID
	addresses []ma.Multiaddr
	// services  []mux.ProtocolID

	privKey ic.PrivKey
	pubKey  ic.PubKey

	// TODO move latency away from peer into the package that uses it. Instead,
	// within that package, map from ID to latency value.
	latency time.Duration

	sync.RWMutex
}

// String prints out the peer.
func (p *peer) String() string {
	return "[Peer " + p.id.String()[:12] + "]"
}

// Key returns the ID as a Key (string) for maps.
func (p *peer) Key() u.Key {
	return u.Key(p.id)
}

// ID returns the peer's ID
func (p *peer) ID() ID {
	return p.id
}

// PrivKey returns the peer's Private Key
func (p *peer) PrivKey() ic.PrivKey {
	return p.privKey
}

// PubKey returns the peer's Private Key
func (p *peer) PubKey() ic.PubKey {
	return p.pubKey
}

// Addresses returns the peer's multiaddrs
func (p *peer) Addresses() []ma.Multiaddr {
	cp := make([]ma.Multiaddr, len(p.addresses))
	p.RLock()
	copy(cp, p.addresses)
	defer p.RUnlock()
	return cp
}

// AddAddress adds the given Multiaddr address to Peer's addresses.
// Returns whether this address was a newly added address
func (p *peer) AddAddress(a ma.Multiaddr) bool {
	p.Lock()
	defer p.Unlock()

	for _, addr := range p.addresses {
		if addr.Equal(a) {
			return false
		}
	}
	p.addresses = append(p.addresses, a)
	return true
}

// NetAddress returns the first Multiaddr found for a given network.
func (p *peer) NetAddress(n string) ma.Multiaddr {
	p.RLock()
	defer p.RUnlock()

	for _, a := range p.addresses {
		for _, p := range a.Protocols() {
			if p.Name == n {
				return a
			}
		}
	}
	return nil
}

// func (p *peer) Services() []mux.ProtocolID {
// 	p.RLock()
// 	defer p.RUnlock()
// 	return p.services
// }
//
// func (p *peer) SetServices(s []mux.ProtocolID) {
// 	p.Lock()
// 	defer p.Unlock()
// 	p.services = s
// }

// GetLatency retrieves the current latency measurement.
func (p *peer) GetLatency() (out time.Duration) {
	p.RLock()
	out = p.latency
	p.RUnlock()
	return
}

// SetLatency sets the latency measurement.
// TODO: Instead of just keeping a single number,
//		 keep a running average over the last hour or so
// Yep, should be EWMA or something. (-jbenet)
func (p *peer) SetLatency(laten time.Duration) {
	p.Lock()
	if p.latency == 0 {
		p.latency = laten
	} else {
		p.latency = ((p.latency * 9) + laten) / 10
	}
	p.Unlock()
}

// LoadAndVerifyKeyPair unmarshalls, loads a private/public key pair.
// Error if (a) unmarshalling fails, or (b) pubkey does not match id.
func (p *peer) LoadAndVerifyKeyPair(marshalled []byte) error {
	sk, err := ic.UnmarshalPrivateKey(marshalled)
	if err != nil {
		return fmt.Errorf("Failed to unmarshal private key: %v", err)
	}

	return p.VerifyAndSetPrivKey(sk)
}

// VerifyAndSetPrivKey sets private key, given its pubkey matches the peer.ID
func (p *peer) VerifyAndSetPrivKey(sk ic.PrivKey) error {

	// construct and assign pubkey. ensure it matches this peer
	if err := p.VerifyAndSetPubKey(sk.GetPublic()); err != nil {
		return err
	}

	p.Lock()
	defer p.Unlock()

	// if we didn't have the priavte key, assign it
	if p.privKey == nil {
		p.privKey = sk
		return nil
	}

	// if we already had the keys, check they're equal.
	if p.privKey.Equals(sk) {
		return nil // as expected. keep the old objects.
	}

	// keys not equal. invariant violated. this warrants a panic.
	// these keys should be _the same_ because peer.ID = H(pk)
	// this mismatch should never happen.
	log.Errorf("%s had PrivKey: %v -- got %v", p, p.privKey, sk)
	panic("invariant violated: unexpected key mismatch")
}

// VerifyAndSetPubKey sets public key, given it matches the peer.ID
func (p *peer) VerifyAndSetPubKey(pk ic.PubKey) error {
	pkid, err := IDFromPubKey(pk)
	if err != nil {
		return fmt.Errorf("Failed to hash public key: %v", err)
	}

	p.Lock()
	defer p.Unlock()

	if !p.id.Equal(pkid) {
		return fmt.Errorf("Public key does not match peer.ID.")
	}

	// if we didn't have the keys, assign them.
	if p.pubKey == nil {
		p.pubKey = pk
		return nil
	}

	// if we already had the pubkey, check they're equal.
	if p.pubKey.Equals(pk) {
		return nil // as expected. keep the old objects.
	}

	// keys not equal. invariant violated. this warrants a panic.
	// these keys should be _the same_ because peer.ID = H(pk)
	// this mismatch should never happen.
	log.Errorf("%s had PubKey: %v -- got %v", p, p.pubKey, pk)
	panic("invariant violated: unexpected key mismatch")
}

// Updates this peer with information from another peer instance
func (p *peer) Update(other Peer) error {
	if !p.ID().Equal(other.ID()) {
		return errors.New("peer ids do not match")
	}

	for _, a := range other.Addresses() {
		p.AddAddress(a)
	}

	p.SetLatency(other.GetLatency())

	sk := other.PrivKey()
	pk := other.PubKey()
	p.Lock()
	if p.privKey == nil {
		p.privKey = sk
	}

	if p.pubKey == nil {
		p.pubKey = pk
	}
	defer p.Unlock()
	return nil
}

// WithKeyPair returns a Peer object with given keys.
func WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error) {
	if sk == nil && pk == nil {
		return nil, fmt.Errorf("PeerWithKeyPair nil keys")
	}

	pk2 := sk.GetPublic()
	if pk == nil {
		pk = pk2
	} else if !pk.Equals(pk2) {
		return nil, fmt.Errorf("key mismatch. pubkey is not privkey's pubkey")
	}

	pkid, err := IDFromPubKey(pk)
	if err != nil {
		return nil, fmt.Errorf("Failed to hash public key: %v", err)
	}

	return &peer{id: pkid, pubKey: pk, privKey: sk}, nil
}

// WithID constructs a peer with given ID.
func WithID(id ID) Peer {
	return &peer{id: id}
}

// WithIDString constructs a peer with given ID (string).
func WithIDString(id string) Peer {
	return WithID(ID(id))
}
<|endoftext|>


<commit_before>// +build linux

package libcontainer

import (
	"fmt"
	"os"
	"testing"

	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/configs"
)

type mockCgroupManager struct {
	pids  []int
	stats *cgroups.Stats
	paths map[string]string
}

func (m *mockCgroupManager) GetPids() ([]int, error) {
	return m.pids, nil
}

func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) {
	return m.stats, nil
}

func (m *mockCgroupManager) Apply(pid int) error {
	return nil
}

func (m *mockCgroupManager) Set(container *configs.Config) error {
	return nil
}

func (m *mockCgroupManager) Destroy() error {
	return nil
}

func (m *mockCgroupManager) GetPaths() map[string]string {
	return m.paths
}

func (m *mockCgroupManager) Freeze(state configs.FreezerState) error {
	return nil
}

type mockProcess struct {
	_pid    int
	started string
}

func (m *mockProcess) terminate() error {
	return nil
}

func (m *mockProcess) pid() int {
	return m._pid
}

func (m *mockProcess) startTime() (string, error) {
	return m.started, nil
}

func (m *mockProcess) start() error {
	return nil
}

func (m *mockProcess) wait() (*os.ProcessState, error) {
	return nil, nil
}

func (m *mockProcess) signal(_ os.Signal) error {
	return nil
}

func TestGetContainerPids(t *testing.T) {
	container := &linuxContainer{
		id:            "myid",
		config:        &configs.Config{},
		cgroupManager: &mockCgroupManager{pids: []int{1, 2, 3}},
	}
	pids, err := container.Processes()
	if err != nil {
		t.Fatal(err)
	}
	for i, expected := range []int{1, 2, 3} {
		if pids[i] != expected {
			t.Fatalf("expected pid %d but received %d", expected, pids[i])
		}
	}
}

func TestGetContainerStats(t *testing.T) {
	container := &linuxContainer{
		id:     "myid",
		config: &configs.Config{},
		cgroupManager: &mockCgroupManager{
			pids: []int{1, 2, 3},
			stats: &cgroups.Stats{
				MemoryStats: cgroups.MemoryStats{
					Usage: 1024,
				},
			},
		},
	}
	stats, err := container.Stats()
	if err != nil {
		t.Fatal(err)
	}
	if stats.CgroupStats == nil {
		t.Fatal("cgroup stats are nil")
	}
	if stats.CgroupStats.MemoryStats.Usage != 1024 {
		t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage)
	}
}

func TestGetContainerState(t *testing.T) {
	var (
		pid                 = os.Getpid()
		expectedMemoryPath  = "/sys/fs/cgroup/memory/myid"
		expectedNetworkPath = "/networks/fd"
	)
	container := &linuxContainer{
		id: "myid",
		config: &configs.Config{
			Namespaces: configs.Namespaces{
				{Type: configs.NEWPID},
				{Type: configs.NEWNS},
				{Type: configs.NEWNET, Path: expectedNetworkPath},
				{Type: configs.NEWUTS},
				{Type: configs.NEWIPC},
			},
		},
		initProcess: &mockProcess{
			_pid:    pid,
			started: "010",
		},
		cgroupManager: &mockCgroupManager{
			pids: []int{1, 2, 3},
			stats: &cgroups.Stats{
				MemoryStats: cgroups.MemoryStats{
					Usage: 1024,
				},
			},
			paths: map[string]string{
				"memory": expectedMemoryPath,
			},
		},
	}
	state, err := container.State()
	if err != nil {
		t.Fatal(err)
	}
	if state.InitProcessPid != pid {
		t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid)
	}
	if state.InitProcessStartTime != "010" {
		t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime)
	}
	paths := state.CgroupPaths
	if paths == nil {
		t.Fatal("cgroup paths should not be nil")
	}
	if memPath := paths["memory"]; memPath != expectedMemoryPath {
		t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath)
	}
	for _, ns := range container.config.Namespaces {
		path := state.NamespacePaths[ns.Type]
		if path == "" {
			t.Fatalf("expected non nil namespace path for %s", ns.Type)
		}
		if ns.Type == configs.NEWNET {
			if path != expectedNetworkPath {
				t.Fatalf("expected path %q but received %q", expectedNetworkPath, path)
			}
		} else {
			file := ""
			switch ns.Type {
			case configs.NEWNET:
				file = "net"
			case configs.NEWNS:
				file = "mnt"
			case configs.NEWPID:
				file = "pid"
			case configs.NEWIPC:
				file = "ipc"
			case configs.NEWUSER:
				file = "user"
			case configs.NEWUTS:
				file = "uts"
			}
			expected := fmt.Sprintf("/proc/%d/ns/%s", pid, file)
			if expected != path {
				t.Fatalf("expected path %q but received %q", expected, path)
			}
		}
	}
}
<commit_msg>Calm down vet about foreign array type<commit_after>// +build linux

package libcontainer

import (
	"fmt"
	"os"
	"testing"

	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/configs"
)

type mockCgroupManager struct {
	pids  []int
	stats *cgroups.Stats
	paths map[string]string
}

func (m *mockCgroupManager) GetPids() ([]int, error) {
	return m.pids, nil
}

func (m *mockCgroupManager) GetStats() (*cgroups.Stats, error) {
	return m.stats, nil
}

func (m *mockCgroupManager) Apply(pid int) error {
	return nil
}

func (m *mockCgroupManager) Set(container *configs.Config) error {
	return nil
}

func (m *mockCgroupManager) Destroy() error {
	return nil
}

func (m *mockCgroupManager) GetPaths() map[string]string {
	return m.paths
}

func (m *mockCgroupManager) Freeze(state configs.FreezerState) error {
	return nil
}

type mockProcess struct {
	_pid    int
	started string
}

func (m *mockProcess) terminate() error {
	return nil
}

func (m *mockProcess) pid() int {
	return m._pid
}

func (m *mockProcess) startTime() (string, error) {
	return m.started, nil
}

func (m *mockProcess) start() error {
	return nil
}

func (m *mockProcess) wait() (*os.ProcessState, error) {
	return nil, nil
}

func (m *mockProcess) signal(_ os.Signal) error {
	return nil
}

func TestGetContainerPids(t *testing.T) {
	container := &linuxContainer{
		id:            "myid",
		config:        &configs.Config{},
		cgroupManager: &mockCgroupManager{pids: []int{1, 2, 3}},
	}
	pids, err := container.Processes()
	if err != nil {
		t.Fatal(err)
	}
	for i, expected := range []int{1, 2, 3} {
		if pids[i] != expected {
			t.Fatalf("expected pid %d but received %d", expected, pids[i])
		}
	}
}

func TestGetContainerStats(t *testing.T) {
	container := &linuxContainer{
		id:     "myid",
		config: &configs.Config{},
		cgroupManager: &mockCgroupManager{
			pids: []int{1, 2, 3},
			stats: &cgroups.Stats{
				MemoryStats: cgroups.MemoryStats{
					Usage: 1024,
				},
			},
		},
	}
	stats, err := container.Stats()
	if err != nil {
		t.Fatal(err)
	}
	if stats.CgroupStats == nil {
		t.Fatal("cgroup stats are nil")
	}
	if stats.CgroupStats.MemoryStats.Usage != 1024 {
		t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage)
	}
}

func TestGetContainerState(t *testing.T) {
	var (
		pid                 = os.Getpid()
		expectedMemoryPath  = "/sys/fs/cgroup/memory/myid"
		expectedNetworkPath = "/networks/fd"
	)
	container := &linuxContainer{
		id: "myid",
		config: &configs.Config{
			Namespaces: []configs.Namespace{
				{Type: configs.NEWPID},
				{Type: configs.NEWNS},
				{Type: configs.NEWNET, Path: expectedNetworkPath},
				{Type: configs.NEWUTS},
				{Type: configs.NEWIPC},
			},
		},
		initProcess: &mockProcess{
			_pid:    pid,
			started: "010",
		},
		cgroupManager: &mockCgroupManager{
			pids: []int{1, 2, 3},
			stats: &cgroups.Stats{
				MemoryStats: cgroups.MemoryStats{
					Usage: 1024,
				},
			},
			paths: map[string]string{
				"memory": expectedMemoryPath,
			},
		},
	}
	state, err := container.State()
	if err != nil {
		t.Fatal(err)
	}
	if state.InitProcessPid != pid {
		t.Fatalf("expected pid %d but received %d", pid, state.InitProcessPid)
	}
	if state.InitProcessStartTime != "010" {
		t.Fatalf("expected process start time 010 but received %s", state.InitProcessStartTime)
	}
	paths := state.CgroupPaths
	if paths == nil {
		t.Fatal("cgroup paths should not be nil")
	}
	if memPath := paths["memory"]; memPath != expectedMemoryPath {
		t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath)
	}
	for _, ns := range container.config.Namespaces {
		path := state.NamespacePaths[ns.Type]
		if path == "" {
			t.Fatalf("expected non nil namespace path for %s", ns.Type)
		}
		if ns.Type == configs.NEWNET {
			if path != expectedNetworkPath {
				t.Fatalf("expected path %q but received %q", expectedNetworkPath, path)
			}
		} else {
			file := ""
			switch ns.Type {
			case configs.NEWNET:
				file = "net"
			case configs.NEWNS:
				file = "mnt"
			case configs.NEWPID:
				file = "pid"
			case configs.NEWIPC:
				file = "ipc"
			case configs.NEWUSER:
				file = "user"
			case configs.NEWUTS:
				file = "uts"
			}
			expected := fmt.Sprintf("/proc/%d/ns/%s", pid, file)
			if expected != path {
				t.Fatalf("expected path %q but received %q", expected, path)
			}
		}
	}
}
<|endoftext|>


<commit_before>package usage

import (
	//	"fmt"
	"github.com/benbjohnson/clock"
	"github.com/raintank/raintank-metric/metric_tank/defcache"
	"github.com/raintank/raintank-metric/metric_tank/struc"
	"github.com/raintank/raintank-metric/schema"
	"sync"
	"time"
)

var Clock clock.Clock
var metrics struc.Metrics
var defCache *defcache.DefCache

type orgstat struct {
	keys   map[string]struct{} // track unique keys seen
	points uint32              // track amount of points seen
}

// tracks for every org
type Usage struct {
	sync.Mutex
	period uint32
	now    map[int]orgstat
	prev   map[int]orgstat
}

func New(period uint32, m struc.Metrics, d *defcache.DefCache, cl clock.Clock) *Usage {
	metrics = m
	defCache = d
	Clock = cl
	return &Usage{
		period: period,
	}
}

func (u *Usage) Add(org int, key string) {
	u.Lock()
	if o, ok := u.now[org]; !ok {
		u.now[org] = orgstat{
			keys: map[string]struct{}{
				key: struct{}{},
			},
			points: 1,
		}
	} else {
		o.keys[key] = struct{}{}
		o.points += 1
		u.now[org] = o
	}
	u.Unlock()
}

func (u *Usage) Report() {
	// provides "clean" ticks at precise intervals, and delivers them shortly after
	tick := func() time.Time {
		now := Clock.Now()
		nowUnix := now.UnixNano()
		p := time.Duration(u.period) * time.Second
		diff := p - (time.Duration(nowUnix) % p)
		ideal := now.Add(diff)
		ticker := Clock.Ticker(diff)
		<-ticker.C
		return ideal
	}
	met := schema.MetricData{
		Interval: int(u.period),
		Tags:     []string{},
	}
	for {
		now := tick().Unix()
		u.Lock()
		u.prev = u.now
		u.now = make(map[int]orgstat)
		for i := range u.prev {
			u.now[i] = orgstat{
				keys:   make(map[string]struct{}),
				points: u.prev[i].points,
			}
		}
		u.Unlock()

		met.Time = now
		for pos, stat := range u.prev {
			met.OrgId = pos - 1

			met.Name = "metric_tank.usage.numSeries"
			met.Metric = met.Name
			met.Unit = "metrics"
			met.TargetType = "gauge"
			met.Value = float64(len(stat.keys))
			met.SetId()

			m := metrics.GetOrCreate(met.Id)
			m.Add(uint32(met.Time), met.Value)
			defCache.Add(&met)

			met.Name = "metric_tank.usage.numPoints"
			met.Metric = met.Name
			met.Unit = "points"
			met.TargetType = "counter"
			met.Value = float64(stat.points)
			met.SetId()

			m = metrics.GetOrCreate(met.Id)
			m.Add(uint32(met.Time), met.Value)
			defCache.Add(&met)
		}
	}
}
<commit_msg>usage: fix reporting<commit_after>package usage

import (
	"github.com/benbjohnson/clock"
	"github.com/raintank/raintank-metric/metric_tank/defcache"
	"github.com/raintank/raintank-metric/metric_tank/struc"
	"github.com/raintank/raintank-metric/schema"
	"sync"
	"time"
)

var Clock clock.Clock
var metrics struc.Metrics
var defCache *defcache.DefCache

type orgstat struct {
	keys   map[string]struct{} // track unique keys seen
	points uint32              // track amount of points seen
}

// tracks for every org
type Usage struct {
	sync.Mutex
	period uint32
	now    map[int]orgstat
	prev   map[int]orgstat
}

func New(period uint32, m struc.Metrics, d *defcache.DefCache, cl clock.Clock) *Usage {
	metrics = m
	defCache = d
	Clock = cl
	ret := &Usage{
		period: period,
		now:    make(map[int]orgstat),
	}
	go ret.Report()
	return ret
}

func (u *Usage) Add(org int, key string) {
	u.Lock()
	if o, ok := u.now[org]; !ok {
		u.now[org] = orgstat{
			keys: map[string]struct{}{
				key: struct{}{},
			},
			points: 1,
		}
	} else {
		o.keys[key] = struct{}{}
		o.points += 1
		u.now[org] = o
	}
	u.Unlock()
}

func (u *Usage) Report() {
	// provides "clean" ticks at precise intervals, and delivers them shortly after
	tick := func() time.Time {
		now := Clock.Now()
		nowUnix := now.UnixNano()
		p := time.Duration(u.period) * time.Second
		diff := p - (time.Duration(nowUnix) % p)
		ideal := now.Add(diff)
		ticker := Clock.Ticker(diff)
		<-ticker.C
		return ideal
	}
	met := schema.MetricData{
		Interval: int(u.period),
		Tags:     []string{},
	}
	for {
		now := tick().Unix()
		u.Lock()
		u.prev = u.now
		u.now = make(map[int]orgstat)
		for i := range u.prev {
			u.now[i] = orgstat{
				keys:   make(map[string]struct{}),
				points: u.prev[i].points,
			}
		}
		u.Unlock()

		met.Time = now
		for org, stat := range u.prev {
			met.OrgId = org

			met.Name = "metric_tank.usage.numSeries"
			met.Metric = met.Name
			met.Unit = "metrics"
			met.TargetType = "gauge"
			met.Value = float64(len(stat.keys))
			met.SetId()

			m := metrics.GetOrCreate(met.Id)
			m.Add(uint32(met.Time), met.Value)
			defCache.Add(&met)

			met.Name = "metric_tank.usage.numPoints"
			met.Metric = met.Name
			met.Unit = "points"
			met.TargetType = "counter"
			met.Value = float64(stat.points)
			met.SetId()

			m = metrics.GetOrCreate(met.Id)
			m.Add(uint32(met.Time), met.Value)
			defCache.Add(&met)
		}
	}
}
<|endoftext|>