<commit_before>// go:generate mockgen -source ./gsb.go -destination mock_gsb_test.go -package va SafeBrowsing

package va

import (
	safebrowsingv4 "github.com/google/safebrowsing"
	"golang.org/x/net/context"

	bgrpc "github.com/letsencrypt/boulder/grpc"
	vaPB "github.com/letsencrypt/boulder/va/proto"
)

// SafeBrowsing is an interface for a third-party safe browsing API client.
type SafeBrowsing interface {
	// IsListed returns a non-empty string if the domain was bad. Specifically,
	// it is which Google Safe Browsing list the domain was found on.
	IsListed(ctx context.Context, url string) (list string, err error)
}

// SafeBrowsingV4 is an interface around the functions from Google
// safebrowsing's v4 API's *SafeBrowser type that we use. Using this interface
// allows mocking for tests
type SafeBrowsingV4 interface {
	LookupURLsContext(ctx context.Context, urls []string) (threats [][]safebrowsingv4.URLThreat, err error)
}

// IsSafeDomain returns true if the domain given is determined to be safe by a
// third-party safe browsing API. It's meant be called by the RA before pending
// authorization creation. If no third-party client was provided, it fails open
// and increments a Skips metric.
func (va *ValidationAuthorityImpl) IsSafeDomain(ctx context.Context, req *vaPB.IsSafeDomainRequest) (*vaPB.IsDomainSafe, error) {
	if req == nil || req.Domain == nil {
		return nil, bgrpc.ErrMissingParameters
	}
	status := va.isSafeDomain(ctx, *req.Domain)
	return &vaPB.IsDomainSafe{IsSafe: &status}, nil
}

// isSafeDomain returns true if the VA considers the given domain safe. If the
// backend errors, we consider the domain safe, so this function never returns
// error.
func (va *ValidationAuthorityImpl) isSafeDomain(ctx context.Context, domain string) bool {
	stats := va.stats.NewScope("IsSafeDomain")
	stats.Inc("IsSafeDomain.Requests", 1)
	if va.safeBrowsing == nil {
		stats.Inc("IsSafeDomain.Skips", 1)
		return true
	}

	list, err := va.safeBrowsing.IsListed(ctx, domain)
	if err != nil {
		stats.Inc("IsSafeDomain.Errors", 1)
		// In the event of an error checking the GSB status we allow the domain in
		// question to be treated as safe to avoid coupling the availability of the
		// VA to the GSB API. This is acceptable for Let's Encrypt because we do not
		// have a hard commitment to GSB filtering in our CP/CPS.
		return true
	}
	stats.Inc("IsSafeDomain.Successes", 1)
	if list == "" {
		stats.Inc("IsSafeDomain.Status.Good", 1)
		return true
	}
	stats.Inc("IsSafeDomain.Status.Bad", 1)
	return false
}
<commit_msg>Ignore canceled IsSafeDomain calls. (#3730)<commit_after>// go:generate mockgen -source ./gsb.go -destination mock_gsb_test.go -package va SafeBrowsing

package va

import (
	safebrowsingv4 "github.com/google/safebrowsing"
	"golang.org/x/net/context"

	"github.com/letsencrypt/boulder/canceled"
	bgrpc "github.com/letsencrypt/boulder/grpc"
	vaPB "github.com/letsencrypt/boulder/va/proto"
)

// SafeBrowsing is an interface for a third-party safe browsing API client.
type SafeBrowsing interface {
	// IsListed returns a non-empty string if the domain was bad. Specifically,
	// it is which Google Safe Browsing list the domain was found on.
	IsListed(ctx context.Context, url string) (list string, err error)
}

// SafeBrowsingV4 is an interface around the functions from Google
// safebrowsing's v4 API's *SafeBrowser type that we use. Using this interface
// allows mocking for tests
type SafeBrowsingV4 interface {
	LookupURLsContext(ctx context.Context, urls []string) (threats [][]safebrowsingv4.URLThreat, err error)
}

// IsSafeDomain returns true if the domain given is determined to be safe by a
// third-party safe browsing API. It's meant be called by the RA before pending
// authorization creation. If no third-party client was provided, it fails open
// and increments a Skips metric.
func (va *ValidationAuthorityImpl) IsSafeDomain(ctx context.Context, req *vaPB.IsSafeDomainRequest) (*vaPB.IsDomainSafe, error) {
	if req == nil || req.Domain == nil {
		return nil, bgrpc.ErrMissingParameters
	}
	status := va.isSafeDomain(ctx, *req.Domain)
	return &vaPB.IsDomainSafe{IsSafe: &status}, nil
}

// isSafeDomain returns true if the VA considers the given domain safe. If the
// backend errors, we consider the domain safe, so this function never returns
// error.
func (va *ValidationAuthorityImpl) isSafeDomain(ctx context.Context, domain string) bool {
	stats := va.stats.NewScope("IsSafeDomain")
	stats.Inc("IsSafeDomain.Requests", 1)
	if va.safeBrowsing == nil {
		stats.Inc("IsSafeDomain.Skips", 1)
		return true
	}

	list, err := va.safeBrowsing.IsListed(ctx, domain)
	if canceled.Is(err) {
		// Sometimes an IsListed request will be canceled because the main
		// validation failed, causing the parent context to be canceled.
		stats.Inc("IsSafeDomain.Canceled", 1)
		return true
	}
	if err != nil {
		stats.Inc("IsSafeDomain.Errors", 1)
		// In the event of an error checking the GSB status we allow the domain in
		// question to be treated as safe to avoid coupling the availability of the
		// VA to the GSB API. This is acceptable for Let's Encrypt because we do not
		// have a hard commitment to GSB filtering in our CP/CPS.
		return true
	}
	stats.Inc("IsSafeDomain.Successes", 1)
	if list == "" {
		stats.Inc("IsSafeDomain.Status.Good", 1)
		return true
	}
	stats.Inc("IsSafeDomain.Status.Bad", 1)
	return false
}
<|endoftext|>


<commit_before>// Package basher provides an API for running and integrating with Bash from Go
package basher

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"syscall"

	"bitbucket.org/kardianos/osext"
)

func exitStatus(err error) (int, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return int(status.ExitStatus()), nil
			}
		}
		return 0, err
	}
	return 0, nil
}

// Application sets up a common entrypoint for a Bash application that
// uses exported Go functions. It uses the DEBUG environment variable
// to set debug on the Context, and SHELL for the Bash binary if it
// includes the string "bash". You can pass a loader function to use
// for the sourced files, and a boolean for whether or not the
// environment should be copied into the Context process.
func Application(
	funcs map[string]func([]string),
	scripts []string,
	loader func(string) ([]byte, error),
	copyEnv bool) {

	var bashPath string
	bashPath, err := exec.LookPath("bash")
	if err != nil {
		if strings.Contains(os.Getenv("SHELL"), "bash") {
			bashPath = os.Getenv("SHELL")
		} else {
			bashPath = "/bin/bash"
		}
	}
	bash, err := NewContext(bashPath, os.Getenv("DEBUG") != "")
	if err != nil {
		log.Fatal(err)
	}
	for name, fn := range funcs {
		bash.ExportFunc(name, fn)
	}
	if bash.HandleFuncs(os.Args) {
		os.Exit(0)
	}

	for _, script := range scripts {
		bash.Source(script, loader)
	}
	if copyEnv {
		bash.CopyEnv()
	}
	status, err := bash.Run("main", os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(status)
}

// A Context is an instance of a Bash interpreter and environment, including
// sourced scripts, environment variables, and embedded Go functions
type Context struct {
	sync.Mutex

	// Debug simply leaves the generated BASH_ENV file produced
	// from each Run call of this Context for debugging.
	Debug bool

	// BashPath is the path to the Bash executable to be used by Run
	BashPath string

	// SelfPath is set by NewContext to be the current executable path.
	// It's used to call back into the calling Go process to run exported
	// functions.
	SelfPath string

	// The io.Reader given to Bash for STDIN
	Stdin io.Reader

	// The io.Writer given to Bash for STDOUT
	Stdout io.Writer

	// The io.Writer given to Bash for STDERR
	Stderr io.Writer

	vars    []string
	scripts [][]byte
	funcs   map[string]func([]string)
}

// Creates and initializes a new Context that will use the given Bash executable.
// The debug mode will leave the produced temporary BASH_ENV file for inspection.
func NewContext(bashpath string, debug bool) (*Context, error) {
	executable, err := osext.Executable()
	if err != nil {
		return nil, err
	}
	return &Context{
		Debug:    debug,
		BashPath: bashpath,
		SelfPath: executable,
		Stdin:    os.Stdin,
		Stdout:   os.Stdout,
		Stderr:   os.Stderr,
		scripts:  make([][]byte, 0),
		vars:     make([]string, 0),
		funcs:    make(map[string]func([]string)),
	}, nil
}

// Copies the current environment variables into the Context
func (c *Context) CopyEnv() {
	c.Lock()
	defer c.Unlock()
	c.vars = append(c.vars, os.Environ()...)
}

// Adds a shell script to the Context environment. The loader argument can be nil
// which means it will use ioutil.Readfile and load from disk, but it exists so you
// can use the Asset function produced by go-bindata when including script files in
// your Go binary. Calls to Source adds files to the environment in order.
func (c *Context) Source(filepath string, loader func(string) ([]byte, error)) error {
	if loader == nil {
		loader = ioutil.ReadFile
	}
	data, err := loader(filepath)
	if err != nil {
		return err
	}
	c.Lock()
	defer c.Unlock()
	c.scripts = append(c.scripts, data)
	return nil
}

// Adds an environment variable to the Context
func (c *Context) Export(name string, value string) {
	c.Lock()
	defer c.Unlock()
	c.vars = append(c.vars, name+"="+value)
}

// Registers a function with the Context that will produce a Bash function in the environment
// that calls back into your executable triggering the function defined as fn.
func (c *Context) ExportFunc(name string, fn func([]string)) {
	c.Lock()
	defer c.Unlock()
	c.funcs[name] = fn
}

// Expects your os.Args to parse and handle any callbacks to Go functions registered with
// ExportFunc. You normally call this at the beginning of your program. If a registered
// function is found and handled, HandleFuncs will exit with the appropriate exit code for you.
func (c *Context) HandleFuncs(args []string) bool {
	for i, arg := range args {
		if arg == "::" && len(args) > i+1 {
			c.Lock()
			defer c.Unlock()
			for cmd := range c.funcs {
				if cmd == args[i+1] {
					c.funcs[cmd](args[i+2:])
					return true
				}
			}
			return false
		}
	}
	return false
}

func (c *Context) buildEnvfile() (string, error) {
	file, err := ioutil.TempFile(os.TempDir(), "bashenv.")
	if err != nil {
		return "", err
	}
	defer file.Close()
	// variables
	file.Write([]byte("unset BASH_ENV\n")) // unset for future calls to bash
	file.Write([]byte("export SELF=" + os.Args[0] + "\n"))
	file.Write([]byte("export EXECUTABLE='" + c.SelfPath + "'\n"))
	for _, kvp := range c.vars {
		file.Write([]byte("export " + strings.Replace(
			strings.Replace(kvp, "'", "\\'", -1), "=", "=$'", 1) + "'\n"))
	}
	// functions
	for cmd := range c.funcs {
		file.Write([]byte(cmd + "() { $EXECUTABLE :: " + cmd + " \"$@\"; }\n"))
	}
	// scripts
	for _, data := range c.scripts {
		file.Write(append(data, '\n'))
	}
	return file.Name(), nil
}

// Runs a command in Bash from this Context. With each call, a temporary file
// is generated used as BASH_ENV when calling Bash that includes all variables,
// sourced scripts, and exported functions from the Context. Standard I/O by
// default is attached to the calling process I/O. You can change this by setting
// the Stdout, Stderr, Stdin variables of the Context.
func (c *Context) Run(command string, args []string) (int, error) {
	c.Lock()
	defer c.Unlock()
	envfile, err := c.buildEnvfile()
	if err != nil {
		return 0, err
	}
	if !c.Debug {
		defer os.Remove(envfile)
	}
	argstring := ""
	for _, arg := range args {
		argstring = argstring + " '" + arg + "'"
	}
	cmd := exec.Command(c.BashPath, "-c", command+argstring)
	cmd.Env = []string{"BASH_ENV=" + envfile}
	cmd.Stdin = c.Stdin
	cmd.Stdout = c.Stdout
	cmd.Stderr = c.Stderr
	return exitStatus(cmd.Run())
}
<commit_msg>Fixing osext import path<commit_after>// Package basher provides an API for running and integrating with Bash from Go
package basher

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"syscall"

	"github.com/kardianos/osext"
)

func exitStatus(err error) (int, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return int(status.ExitStatus()), nil
			}
		}
		return 0, err
	}
	return 0, nil
}

// Application sets up a common entrypoint for a Bash application that
// uses exported Go functions. It uses the DEBUG environment variable
// to set debug on the Context, and SHELL for the Bash binary if it
// includes the string "bash". You can pass a loader function to use
// for the sourced files, and a boolean for whether or not the
// environment should be copied into the Context process.
func Application(
	funcs map[string]func([]string),
	scripts []string,
	loader func(string) ([]byte, error),
	copyEnv bool) {

	var bashPath string
	bashPath, err := exec.LookPath("bash")
	if err != nil {
		if strings.Contains(os.Getenv("SHELL"), "bash") {
			bashPath = os.Getenv("SHELL")
		} else {
			bashPath = "/bin/bash"
		}
	}
	bash, err := NewContext(bashPath, os.Getenv("DEBUG") != "")
	if err != nil {
		log.Fatal(err)
	}
	for name, fn := range funcs {
		bash.ExportFunc(name, fn)
	}
	if bash.HandleFuncs(os.Args) {
		os.Exit(0)
	}

	for _, script := range scripts {
		bash.Source(script, loader)
	}
	if copyEnv {
		bash.CopyEnv()
	}
	status, err := bash.Run("main", os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(status)
}

// A Context is an instance of a Bash interpreter and environment, including
// sourced scripts, environment variables, and embedded Go functions
type Context struct {
	sync.Mutex

	// Debug simply leaves the generated BASH_ENV file produced
	// from each Run call of this Context for debugging.
	Debug bool

	// BashPath is the path to the Bash executable to be used by Run
	BashPath string

	// SelfPath is set by NewContext to be the current executable path.
	// It's used to call back into the calling Go process to run exported
	// functions.
	SelfPath string

	// The io.Reader given to Bash for STDIN
	Stdin io.Reader

	// The io.Writer given to Bash for STDOUT
	Stdout io.Writer

	// The io.Writer given to Bash for STDERR
	Stderr io.Writer

	vars    []string
	scripts [][]byte
	funcs   map[string]func([]string)
}

// Creates and initializes a new Context that will use the given Bash executable.
// The debug mode will leave the produced temporary BASH_ENV file for inspection.
func NewContext(bashpath string, debug bool) (*Context, error) {
	executable, err := osext.Executable()
	if err != nil {
		return nil, err
	}
	return &Context{
		Debug:    debug,
		BashPath: bashpath,
		SelfPath: executable,
		Stdin:    os.Stdin,
		Stdout:   os.Stdout,
		Stderr:   os.Stderr,
		scripts:  make([][]byte, 0),
		vars:     make([]string, 0),
		funcs:    make(map[string]func([]string)),
	}, nil
}

// Copies the current environment variables into the Context
func (c *Context) CopyEnv() {
	c.Lock()
	defer c.Unlock()
	c.vars = append(c.vars, os.Environ()...)
}

// Adds a shell script to the Context environment. The loader argument can be nil
// which means it will use ioutil.Readfile and load from disk, but it exists so you
// can use the Asset function produced by go-bindata when including script files in
// your Go binary. Calls to Source adds files to the environment in order.
func (c *Context) Source(filepath string, loader func(string) ([]byte, error)) error {
	if loader == nil {
		loader = ioutil.ReadFile
	}
	data, err := loader(filepath)
	if err != nil {
		return err
	}
	c.Lock()
	defer c.Unlock()
	c.scripts = append(c.scripts, data)
	return nil
}

// Adds an environment variable to the Context
func (c *Context) Export(name string, value string) {
	c.Lock()
	defer c.Unlock()
	c.vars = append(c.vars, name+"="+value)
}

// Registers a function with the Context that will produce a Bash function in the environment
// that calls back into your executable triggering the function defined as fn.
func (c *Context) ExportFunc(name string, fn func([]string)) {
	c.Lock()
	defer c.Unlock()
	c.funcs[name] = fn
}

// Expects your os.Args to parse and handle any callbacks to Go functions registered with
// ExportFunc. You normally call this at the beginning of your program. If a registered
// function is found and handled, HandleFuncs will exit with the appropriate exit code for you.
func (c *Context) HandleFuncs(args []string) bool {
	for i, arg := range args {
		if arg == "::" && len(args) > i+1 {
			c.Lock()
			defer c.Unlock()
			for cmd := range c.funcs {
				if cmd == args[i+1] {
					c.funcs[cmd](args[i+2:])
					return true
				}
			}
			return false
		}
	}
	return false
}

func (c *Context) buildEnvfile() (string, error) {
	file, err := ioutil.TempFile(os.TempDir(), "bashenv.")
	if err != nil {
		return "", err
	}
	defer file.Close()
	// variables
	file.Write([]byte("unset BASH_ENV\n")) // unset for future calls to bash
	file.Write([]byte("export SELF=" + os.Args[0] + "\n"))
	file.Write([]byte("export EXECUTABLE='" + c.SelfPath + "'\n"))
	for _, kvp := range c.vars {
		file.Write([]byte("export " + strings.Replace(
			strings.Replace(kvp, "'", "\\'", -1), "=", "=$'", 1) + "'\n"))
	}
	// functions
	for cmd := range c.funcs {
		file.Write([]byte(cmd + "() { $EXECUTABLE :: " + cmd + " \"$@\"; }\n"))
	}
	// scripts
	for _, data := range c.scripts {
		file.Write(append(data, '\n'))
	}
	return file.Name(), nil
}

// Runs a command in Bash from this Context. With each call, a temporary file
// is generated used as BASH_ENV when calling Bash that includes all variables,
// sourced scripts, and exported functions from the Context. Standard I/O by
// default is attached to the calling process I/O. You can change this by setting
// the Stdout, Stderr, Stdin variables of the Context.
func (c *Context) Run(command string, args []string) (int, error) {
	c.Lock()
	defer c.Unlock()
	envfile, err := c.buildEnvfile()
	if err != nil {
		return 0, err
	}
	if !c.Debug {
		defer os.Remove(envfile)
	}
	argstring := ""
	for _, arg := range args {
		argstring = argstring + " '" + arg + "'"
	}
	cmd := exec.Command(c.BashPath, "-c", command+argstring)
	cmd.Env = []string{"BASH_ENV=" + envfile}
	cmd.Stdin = c.Stdin
	cmd.Stdout = c.Stdout
	cmd.Stderr = c.Stderr
	return exitStatus(cmd.Run())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"syscall"
)

func main() {
	var dependencies []StaticLibrary
	parallels := 0
	done := make(chan bool)

	// set parallel numbers
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Parse flags
	version := flag.String("v", NGINX_VERSION, "nginx version")
	nginxConfigurePath := flag.String("c", "", "configuration file for building nginx")
	modulesConfPath := flag.String("m", "", "configuration file for 3rd party modules")
	workParentDir := flag.String("d", "", "working directory")
	jobs := flag.Int("j", runtime.NumCPU(), "jobs to build nginx")
	verbose := flag.Bool("verbose", false, "verbose mode")
	pcreStatic := flag.Bool("pcre", false, "embedded PCRE statically")
	pcreVersion := flag.String("pcreversion", PCRE_VERSION, "PCRE version")
	openSSLStatic := flag.Bool("openssl", false, "embedded OpenSSL statically")
	openSSLVersion := flag.String("opensslversion", OPENSSL_VERSION, "OpenSSL version")
	zlibStatic := flag.Bool("zlib", false, "embedded zlib statically")
	zlibVersion := flag.String("zlibversion", ZLIB_VERSION, "zlib version")
	clear := flag.Bool("clear", false, "remove entries in working directory")
	versionPrint := flag.Bool("version", false, "print nginx-build versions")
	versionsPrint := flag.Bool("versions", false, "print nginx versions")
	openResty := flag.Bool("openresty", false, "download openresty instead of nginx")
	tengine := flag.Bool("tengine", false, "download tengine instead of nginx")
	openRestyVersion := flag.String("openrestyversion", OPENRESTY_VERSION, "openresty version")
	tengineVersion := flag.String("tengineversion", TENGINE_VERSION, "tengine version")
	configureOnly := flag.Bool("configureonly", false, "configuring nginx only not building")

	var configureOptions ConfigureOptions
	argsString := makeArgsString()
	argsBool := makeArgsBool()
	var multiflag StringFlag

	for k, v := range argsString {
		if k == "add-module" {
			flag.Var(&multiflag, k, v.Desc)
		} else {
			v.Value = flag.String(k, "", v.Desc)
			argsString[k] = v
		}
	}

	for k, v := range argsBool {
		v.Enabled = flag.Bool(k, false, v.Desc)
		argsBool[k] = v
	}

	flag.Parse()

	// Allow multiple flags for `--add-module`
	{
		tmp := argsString["add-module"]
		tmp_ := multiflag.String()
		tmp.Value = &tmp_
		argsString["add-module"] = tmp
	}

	configureOptions.Values = argsString
	configureOptions.Bools = argsBool

	if *versionPrint {
		printNginxBuildVersion()
		os.Exit(0)
	}

	if *versionsPrint {
		printNginxVersions()
		os.Exit(0)
	}

	printFirstMsg()

	// set verbose mode
	VerboseEnabled = *verbose

	var nginxBuilder Builder
	if *openResty && *tengine {
		log.Fatal("select one between '-openresty' and '-tengine'.")
	}
	if *openResty {
		nginxBuilder = makeBuilder(COMPONENT_OPENRESTY, *openRestyVersion)
	} else if *tengine {
		nginxBuilder = makeBuilder(COMPONENT_TENGINE, *tengineVersion)
	} else {
		nginxBuilder = makeBuilder(COMPONENT_NGINX, *version)
	}
	pcreBuilder := makeBuilder(COMPONENT_PCRE, *pcreVersion)
	openSSLBuilder := makeBuilder(COMPONENT_OPENSSL, *openSSLVersion)
	zlibBuilder := makeBuilder(COMPONENT_ZLIB, *zlibVersion)

	// change default umask
	_ = syscall.Umask(0)

	versionCheck(*version)

	nginxConfigure, err := fileGetContents(*nginxConfigurePath)
	if err != nil {
		log.Fatal(err.Error())
	}
	nginxConfigure = normalizeConfigure(nginxConfigure)

	modules3rd, err := loadModules3rdFile(*modulesConfPath)
	if err != nil {
		log.Fatal(err.Error())
	}

	if len(*workParentDir) == 0 {
		log.Fatal("set working directory with -d")
	}

	if !fileExists(*workParentDir) {
		err := os.Mkdir(*workParentDir, 0755)
		if err != nil {
			log.Fatalf("Failed to create working directory(%s) does not exist.", *workParentDir)
		}
	}

	var workDir string
	if *openResty {
		workDir = *workParentDir + "/" + *openRestyVersion
	} else if *tengine {
		workDir = *workParentDir + "/" + *tengineVersion
	} else {
		workDir = *workParentDir + "/" + *version
	}
	if *clear {
		err := clearWorkDir(workDir)
		if err != nil {
			log.Fatal(err.Error())
		}
	}

	if !fileExists(workDir) {
		err := os.Mkdir(workDir, 0755)
		if err != nil {
			log.Fatalf("Failed to create working directory(%s) does not exist.", workDir)
		}
	}

	rootDir := saveCurrentDir()
	// cd workDir
	err = os.Chdir(workDir)
	if err != nil {
		log.Fatal(err.Error())
	}

	if *pcreStatic {
		parallels++
		go downloadAndExtractParallel(&pcreBuilder, done)
	}

	if *openSSLStatic {
		parallels++
		go downloadAndExtractParallel(&openSSLBuilder, done)
	}

	if *zlibStatic {
		parallels++
		go downloadAndExtractParallel(&zlibBuilder, done)
	}

	parallels++
	go downloadAndExtractParallel(&nginxBuilder, done)

	if len(modules3rd) > 0 {
		parallels += len(modules3rd)
		for _, m := range modules3rd {
			go downloadAndExtractModule3rdParallel(m, done)
		}

	}

	// wait until all downloading processes by goroutine finish
	for i := 0; i < parallels; i++ {
		<-done
	}

	if len(modules3rd) > 0 {
		for _, m := range modules3rd {
			provideModule3rd(&m)
		}
	}

	// cd workDir/nginx-${version}
	os.Chdir(nginxBuilder.sourcePath())

	if *pcreStatic {
		dependencies = append(dependencies, makeStaticLibrary(&pcreBuilder))
	}

	if *openSSLStatic {
		dependencies = append(dependencies, makeStaticLibrary(&openSSLBuilder))
	}

	if *zlibStatic {
		dependencies = append(dependencies, makeStaticLibrary(&zlibBuilder))
	}

	log.Printf("Generate configure script for %s.....", nginxBuilder.sourcePath())

	if *pcreStatic && pcreBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(pcreBuilder.warnMsgWithLibrary())
	}

	if *openSSLStatic && openSSLBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(openSSLBuilder.warnMsgWithLibrary())

	}

	if *zlibStatic && zlibBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(zlibBuilder.warnMsgWithLibrary())
	}

	if strings.Contains(nginxConfigure, "--add-module=") {
		log.Println("[warn]Using '--add-module' is discouraged. Instead give ini-file with '-m' to 'nginx-build'")
	}

	configureScript := configureGen(nginxConfigure, modules3rd, dependencies, configureOptions, rootDir)
	err = ioutil.WriteFile("./nginx-configure", []byte(configureScript), 0655)
	if err != nil {
		log.Fatalf("Failed to generate configure script for %s", nginxBuilder.sourcePath())
	}
	log.Printf("Configure %s.....", nginxBuilder.sourcePath())
	err = configureNginx()
	if err != nil {
		log.Printf("Failed to configure %s\n", nginxBuilder.sourcePath())
		printFatalMsg(err, "nginx-configure.log")
	}

	if *configureOnly {
		printLastMsg(workDir, nginxBuilder.sourcePath(), *openResty, *configureOnly)
		return
	}

	log.Printf("Build %s.....", nginxBuilder.sourcePath())
	if *openSSLStatic {
		// Workarounds for protecting a failure of building nginx with static-linked OpenSSL.

		// Unfortunately a build of OpenSSL fails when multi-CPUs are used.
		*jobs = 1

		// Sometimes machine hardware name('uname -m') is different
		// from machine processor architecture name('uname -p') on Mac.
		// Specifically, `uname -p` is 'i386' and `uname -m` is 'x86_64'.
		// In this case, a build of OpenSSL fails.
		// So it needs to convince OpenSSL with KERNEL_BITS.
		if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" {
			os.Setenv("KERNEL_BITS", "64")
		}
	}
	err = buildNginx(*jobs)
	if err != nil {
		log.Printf("Failed to build %s\n", nginxBuilder.sourcePath())
		printFatalMsg(err, "nginx-build.log")
	}

	printLastMsg(workDir, nginxBuilder.sourcePath(), *openResty, *configureOnly)

	// cd rootDir
	os.Chdir(rootDir)
}
<commit_msg>refactored.<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"syscall"
)

func main() {
	var dependencies []StaticLibrary
	parallels := 0
	done := make(chan bool)

	// set parallel numbers
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Parse flags
	version := flag.String("v", NGINX_VERSION, "nginx version")
	nginxConfigurePath := flag.String("c", "", "configuration file for building nginx")
	modulesConfPath := flag.String("m", "", "configuration file for 3rd party modules")
	workParentDir := flag.String("d", "", "working directory")
	jobs := flag.Int("j", runtime.NumCPU(), "jobs to build nginx")
	verbose := flag.Bool("verbose", false, "verbose mode")
	pcreStatic := flag.Bool("pcre", false, "embedded PCRE statically")
	pcreVersion := flag.String("pcreversion", PCRE_VERSION, "PCRE version")
	openSSLStatic := flag.Bool("openssl", false, "embedded OpenSSL statically")
	openSSLVersion := flag.String("opensslversion", OPENSSL_VERSION, "OpenSSL version")
	zlibStatic := flag.Bool("zlib", false, "embedded zlib statically")
	zlibVersion := flag.String("zlibversion", ZLIB_VERSION, "zlib version")
	clear := flag.Bool("clear", false, "remove entries in working directory")
	versionPrint := flag.Bool("version", false, "print nginx-build versions")
	versionsPrint := flag.Bool("versions", false, "print nginx versions")
	openResty := flag.Bool("openresty", false, "download openresty instead of nginx")
	tengine := flag.Bool("tengine", false, "download tengine instead of nginx")
	openRestyVersion := flag.String("openrestyversion", OPENRESTY_VERSION, "openresty version")
	tengineVersion := flag.String("tengineversion", TENGINE_VERSION, "tengine version")
	configureOnly := flag.Bool("configureonly", false, "configuring nginx only not building")

	var configureOptions ConfigureOptions
	argsString := makeArgsString()
	argsBool := makeArgsBool()
	var multiflag StringFlag

	for k, v := range argsString {
		if k == "add-module" {
			flag.Var(&multiflag, k, v.Desc)
		} else {
			v.Value = flag.String(k, "", v.Desc)
			argsString[k] = v
		}
	}

	for k, v := range argsBool {
		v.Enabled = flag.Bool(k, false, v.Desc)
		argsBool[k] = v
	}

	flag.Parse()

	// Allow multiple flags for `--add-module`
	{
		tmp := argsString["add-module"]
		tmp_ := multiflag.String()
		tmp.Value = &tmp_
		argsString["add-module"] = tmp
	}

	configureOptions.Values = argsString
	configureOptions.Bools = argsBool

	if *versionPrint {
		printNginxBuildVersion()
		os.Exit(0)
	}

	if *versionsPrint {
		printNginxVersions()
		os.Exit(0)
	}

	printFirstMsg()

	// set verbose mode
	VerboseEnabled = *verbose

	var nginxBuilder Builder
	if *openResty && *tengine {
		log.Fatal("select one between '-openresty' and '-tengine'.")
	}
	if *openResty {
		nginxBuilder = makeBuilder(COMPONENT_OPENRESTY, *openRestyVersion)
	} else if *tengine {
		nginxBuilder = makeBuilder(COMPONENT_TENGINE, *tengineVersion)
	} else {
		nginxBuilder = makeBuilder(COMPONENT_NGINX, *version)
	}
	pcreBuilder := makeBuilder(COMPONENT_PCRE, *pcreVersion)
	openSSLBuilder := makeBuilder(COMPONENT_OPENSSL, *openSSLVersion)
	zlibBuilder := makeBuilder(COMPONENT_ZLIB, *zlibVersion)

	// change default umask
	_ = syscall.Umask(0)

	versionCheck(*version)

	nginxConfigure, err := fileGetContents(*nginxConfigurePath)
	if err != nil {
		log.Fatal(err.Error())
	}
	nginxConfigure = normalizeConfigure(nginxConfigure)

	modules3rd, err := loadModules3rdFile(*modulesConfPath)
	if err != nil {
		log.Fatal(err.Error())
	}

	if len(*workParentDir) == 0 {
		log.Fatal("set working directory with -d")
	}

	if !fileExists(*workParentDir) {
		err := os.Mkdir(*workParentDir, 0755)
		if err != nil {
			log.Fatalf("Failed to create working directory(%s) does not exist.", *workParentDir)
		}
	}

	var workDir string
	if *openResty {
		workDir = *workParentDir + "/" + *openRestyVersion
	} else if *tengine {
		workDir = *workParentDir + "/" + *tengineVersion
	} else {
		workDir = *workParentDir + "/" + *version
	}
	if *clear {
		err := clearWorkDir(workDir)
		if err != nil {
			log.Fatal(err.Error())
		}
	}

	if !fileExists(workDir) {
		err := os.Mkdir(workDir, 0755)
		if err != nil {
			log.Fatalf("Failed to create working directory(%s) does not exist.", workDir)
		}
	}

	rootDir := saveCurrentDir()
	// cd workDir
	err = os.Chdir(workDir)
	if err != nil {
		log.Fatal(err.Error())
	}

	if *pcreStatic {
		parallels++
		go downloadAndExtractParallel(&pcreBuilder, done)
	}

	if *openSSLStatic {
		parallels++
		go downloadAndExtractParallel(&openSSLBuilder, done)
	}

	if *zlibStatic {
		parallels++
		go downloadAndExtractParallel(&zlibBuilder, done)
	}

	parallels++
	go downloadAndExtractParallel(&nginxBuilder, done)

	if len(modules3rd) > 0 {
		parallels += len(modules3rd)
		for _, m := range modules3rd {
			go downloadAndExtractModule3rdParallel(m, done)
		}

	}

	// wait until all downloading processes by goroutine finish
	for i := 0; i < parallels; i++ {
		<-done
	}

	if len(modules3rd) > 0 {
		for _, m := range modules3rd {
			provideModule3rd(&m)
		}
	}

	// cd workDir/nginx-${version}
	os.Chdir(nginxBuilder.sourcePath())

	if *pcreStatic {
		dependencies = append(dependencies, makeStaticLibrary(&pcreBuilder))
	}

	if *openSSLStatic {
		dependencies = append(dependencies, makeStaticLibrary(&openSSLBuilder))
	}

	if *zlibStatic {
		dependencies = append(dependencies, makeStaticLibrary(&zlibBuilder))
	}

	log.Printf("Generate configure script for %s.....", nginxBuilder.sourcePath())

	if *pcreStatic && pcreBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(pcreBuilder.warnMsgWithLibrary())
	}

	if *openSSLStatic && openSSLBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(openSSLBuilder.warnMsgWithLibrary())

	}

	if *zlibStatic && zlibBuilder.isIncludeWithOption(nginxConfigure) {
		log.Printf(zlibBuilder.warnMsgWithLibrary())
	}

	if strings.Contains(nginxConfigure, "--add-module=") {
		log.Println("[warn]Using '--add-module' is discouraged. Instead give ini-file with '-m' to 'nginx-build'")
	}

	configureScript := configureGen(nginxConfigure, modules3rd, dependencies, configureOptions, rootDir)

	err = ioutil.WriteFile("./nginx-configure", []byte(configureScript), 0655)
	if err != nil {
		log.Fatalf("Failed to generate configure script for %s", nginxBuilder.sourcePath())
	}

	log.Printf("Configure %s.....", nginxBuilder.sourcePath())

	err = configureNginx()
	if err != nil {
		log.Printf("Failed to configure %s\n", nginxBuilder.sourcePath())
		printFatalMsg(err, "nginx-configure.log")
	}

	if *configureOnly {
		printLastMsg(workDir, nginxBuilder.sourcePath(), *openResty, *configureOnly)
		return
	}

	log.Printf("Build %s.....", nginxBuilder.sourcePath())

	if *openSSLStatic {
		// Workarounds for protecting a failure of building nginx with static-linked OpenSSL.

		// Unfortunately a build of OpenSSL fails when multi-CPUs are used.
		*jobs = 1

		// Sometimes machine hardware name('uname -m') is different
		// from machine processor architecture name('uname -p') on Mac.
		// Specifically, `uname -p` is 'i386' and `uname -m` is 'x86_64'.
		// In this case, a build of OpenSSL fails.
		// So it needs to convince OpenSSL with KERNEL_BITS.
		if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" {
			os.Setenv("KERNEL_BITS", "64")
		}
	}

	err = buildNginx(*jobs)
	if err != nil {
		log.Printf("Failed to build %s\n", nginxBuilder.sourcePath())
		printFatalMsg(err, "nginx-build.log")
	}

	printLastMsg(workDir, nginxBuilder.sourcePath(), *openResty, *configureOnly)

	// cd rootDir
	os.Chdir(rootDir)
}
<|endoftext|>


<commit_before>// A go implementation in the spirit of the python ConfigParser
package goconfigparser

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

// see python3 configparser.py
var sectionRE = regexp.MustCompile(`^\[(?P<header>[^]]+)\]`)
var optionRE = regexp.MustCompile(`^(?P<option>.*?)\s*(?P<vi>[=|:])\s*(?P<value>.*)$`)
var commentRE = regexp.MustCompile(`^\s*[#;].*$`)

var booleanStates = map[string]bool{
	"1": true, "yes": true, "true": true, "on": true,
	"0": false, "no": false, "false": false, "off": false}

type NoOptionError struct {
	s string
}

func (e NoOptionError) Error() string {
	return e.s
}
func newNoOptionError(section, option string) *NoOptionError {
	return &NoOptionError{s: fmt.Sprintf("No option %s in section %s", option, section)}
}

type NoSectionError struct {
	s string
}

func (e NoSectionError) Error() string {
	return e.s
}
func newNoSectionError(section string) *NoSectionError {
	return &NoSectionError{s: fmt.Sprintf("No section: %s", section)}
}

type ConfigParser struct {
	sections map[string]Section

	// allow data with no ["section"] header via Get("", key)
	AllowNoSectionHeader bool
}

type Section struct {
	options map[string][]string
}

// Create a new empty ConfigParser
func New() (cfg *ConfigParser) {
	return &ConfigParser{
		sections: make(map[string]Section)}
}

// Return a string slice of the sections available
func (c *ConfigParser) Sections() (res []string) {
	for k, _ := range c.sections {
		res = append(res, k)
	}
	return res
}

// Return a string slice of the options available in the given section
func (c *ConfigParser) Options(section string) (res []string, err error) {
	sect, ok := c.sections[section]
	if !ok {
		return res, newNoSectionError(section)
	}
	for k, _ := range sect.options {
		res = append(res, k)
	}
	return res, err
}

// Attempt to parse the given string as a configuration
// It may return a error if the parsing fails
func (c *ConfigParser) ReadString(s string) (err error) {
	r := strings.NewReader(s)
	return c.Read(r)
}

// Attempt to parse the given file as a configuration
// It may return a error if the parsing fails
func (c *ConfigParser) ReadFile(path string) (err error) {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	return c.Read(f)
}

// Attempt to parse the given io.Reader as a configuration
// It may return a error if the reading fails
func (c *ConfigParser) Read(r io.Reader) (err error) {
	scanner := bufio.NewScanner(r)

	curSect := ""
	// we allow files with no [section] header in this mode, by
	// default its a error to be aligned with what python configparser
	// is doing
	if c.AllowNoSectionHeader {
		c.sections[""] = Section{
			options: make(map[string][]string)}
	}
	indentLevel := 0
	curOption := ""
	for scanner.Scan() {
		line := scanner.Text()
		if commentRE.MatchString(line) {
			// Do nothing
		} else {
			cur_indent_level := len(line) - len(strings.TrimLeft(line, " "))
			if curSect != "" && curOption != "" && cur_indent_level > indentLevel {
				c.sections[curSect].options[curOption] = append(c.sections[curSect].options[curOption],
					strings.TrimSpace(line))
				// a section header or option header?
			} else if sectionRE.MatchString(line) {
				indentLevel = cur_indent_level
				matches := sectionRE.FindStringSubmatch(line)
				curSect = matches[1]
				curOption = ""
				c.sections[curSect] = Section{
					options: make(map[string][]string)}
			} else if optionRE.MatchString(line) {
				matches := optionRE.FindStringSubmatch(line)
				key := matches[1]
				value := matches[3]
				value = strings.Replace(value, "%%", "%", -1)
				if _, ok := c.sections[curSect]; !ok {
					return newNoSectionError(curSect)
				}
				// in case of continuation line, value could be empty
				if value != "" {
					c.sections[curSect].options[key] = append(c.sections[curSect].options[key], value)
				}
				curOption = key
			}
		}
	}
	if err := scanner.Err(); err != nil {
		log.Printf("ConfigParser scan error %s from %s", err, r)
	}
	return err
}

// Return the option for the given section as string or an error
func (c *ConfigParser) Get(section, option string) (val string, err error) {
	if _, ok := c.sections[section]; !ok {
		return val, newNoSectionError(section)
	}
	sec := c.sections[section]

	if _, ok := sec.options[option]; !ok {
		return val, newNoOptionError(section, option)
	}

	return strings.Join(sec.options[option], "\n"), err
}

// Return the option for the given section as integer or an error
func (c *ConfigParser) Getint(section, option string) (val int, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}
	return strconv.Atoi(sv)
}

// Return the option for the given section as float or an error
func (c *ConfigParser) Getfloat(section, option string) (val float64, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}
	return strconv.ParseFloat(sv, 64)
}

// Return the option for the given section as boolean or an error
func (c *ConfigParser) Getbool(section, option string) (val bool, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}

	val, ok := booleanStates[strings.ToLower(sv)]
	if !ok {
		return val, errors.New(fmt.Sprintf("No boolean: %s", sv))
	}

	return val, err
}
<commit_msg>goconfigparser: fix static check errors<commit_after>// A go implementation in the spirit of the python ConfigParser
package goconfigparser

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

// see python3 configparser.py
var sectionRE = regexp.MustCompile(`^\[(?P<header>[^]]+)\]`)
var optionRE = regexp.MustCompile(`^(?P<option>.*?)\s*(?P<vi>[=|:])\s*(?P<value>.*)$`)
var commentRE = regexp.MustCompile(`^\s*[#;].*$`)

var booleanStates = map[string]bool{
	"1": true, "yes": true, "true": true, "on": true,
	"0": false, "no": false, "false": false, "off": false}

type NoOptionError struct {
	s string
}

func (e NoOptionError) Error() string {
	return e.s
}
func newNoOptionError(section, option string) *NoOptionError {
	return &NoOptionError{s: fmt.Sprintf("No option %s in section %s", option, section)}
}

type NoSectionError struct {
	s string
}

func (e NoSectionError) Error() string {
	return e.s
}
func newNoSectionError(section string) *NoSectionError {
	return &NoSectionError{s: fmt.Sprintf("No section: %s", section)}
}

type ConfigParser struct {
	sections map[string]Section

	// allow data with no ["section"] header via Get("", key)
	AllowNoSectionHeader bool
}

type Section struct {
	options map[string][]string
}

// Create a new empty ConfigParser
func New() (cfg *ConfigParser) {
	return &ConfigParser{
		sections: make(map[string]Section)}
}

// Return a string slice of the sections available
func (c *ConfigParser) Sections() (res []string) {
	for k := range c.sections {
		res = append(res, k)
	}
	return res
}

// Return a string slice of the options available in the given section
func (c *ConfigParser) Options(section string) (res []string, err error) {
	sect, ok := c.sections[section]
	if !ok {
		return res, newNoSectionError(section)
	}
	for k := range sect.options {
		res = append(res, k)
	}
	return res, err
}

// Attempt to parse the given string as a configuration
// It may return a error if the parsing fails
func (c *ConfigParser) ReadString(s string) (err error) {
	r := strings.NewReader(s)
	return c.Read(r)
}

// Attempt to parse the given file as a configuration
// It may return a error if the parsing fails
func (c *ConfigParser) ReadFile(path string) (err error) {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	return c.Read(f)
}

// Attempt to parse the given io.Reader as a configuration
// It may return a error if the reading fails
func (c *ConfigParser) Read(r io.Reader) (err error) {
	scanner := bufio.NewScanner(r)

	curSect := ""
	// we allow files with no [section] header in this mode, by
	// default its a error to be aligned with what python configparser
	// is doing
	if c.AllowNoSectionHeader {
		c.sections[""] = Section{
			options: make(map[string][]string)}
	}
	indentLevel := 0
	curOption := ""
	for scanner.Scan() {
		line := scanner.Text()
		if commentRE.MatchString(line) {
			// Do nothing
		} else {
			cur_indent_level := len(line) - len(strings.TrimLeft(line, " "))
			if curSect != "" && curOption != "" && cur_indent_level > indentLevel {
				c.sections[curSect].options[curOption] = append(c.sections[curSect].options[curOption],
					strings.TrimSpace(line))
				// a section header or option header?
			} else if sectionRE.MatchString(line) {
				indentLevel = cur_indent_level
				matches := sectionRE.FindStringSubmatch(line)
				curSect = matches[1]
				curOption = ""
				c.sections[curSect] = Section{
					options: make(map[string][]string)}
			} else if optionRE.MatchString(line) {
				matches := optionRE.FindStringSubmatch(line)
				key := matches[1]
				value := matches[3]
				value = strings.Replace(value, "%%", "%", -1)
				if _, ok := c.sections[curSect]; !ok {
					return newNoSectionError(curSect)
				}
				// in case of continuation line, value could be empty
				if value != "" {
					c.sections[curSect].options[key] = append(c.sections[curSect].options[key], value)
				}
				curOption = key
			}
		}
	}
	if err := scanner.Err(); err != nil {
		log.Printf("ConfigParser scan error %s from %s", err, r)
	}
	return err
}

// Return the option for the given section as string or an error
func (c *ConfigParser) Get(section, option string) (val string, err error) {
	if _, ok := c.sections[section]; !ok {
		return val, newNoSectionError(section)
	}
	sec := c.sections[section]

	if _, ok := sec.options[option]; !ok {
		return val, newNoOptionError(section, option)
	}

	return strings.Join(sec.options[option], "\n"), err
}

// Return the option for the given section as integer or an error
func (c *ConfigParser) Getint(section, option string) (val int, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}
	return strconv.Atoi(sv)
}

// Return the option for the given section as float or an error
func (c *ConfigParser) Getfloat(section, option string) (val float64, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}
	return strconv.ParseFloat(sv, 64)
}

// Return the option for the given section as boolean or an error
func (c *ConfigParser) Getbool(section, option string) (val bool, err error) {
	sv, err := c.Get(section, option)
	if err != nil {
		return val, err
	}

	val, ok := booleanStates[strings.ToLower(sv)]
	if !ok {
		return val, fmt.Errorf("No boolean: %s", sv)
	}

	return val, err
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/kardianos/osext"
	"github.com/keybase/go-updater"
	"github.com/keybase/go-updater/command"
	"github.com/keybase/go-updater/process"
	"github.com/keybase/go-updater/util"
)

// execPath returns the app bundle path where this executable is located
func (c config) execPath() string {
	path, err := osext.Executable()
	if err != nil {
		c.log.Warningf("Error trying to determine our executable path: %s", err)
		return ""
	}
	return path
}

// destinationPath returns the app bundle path where this executable is located
func (c config) destinationPath() string {
	return appBundleForPath(c.execPath())
}

func appBundleForPath(path string) string {
	if path == "" {
		return ""
	}
	paths := strings.SplitN(path, ".app", 2)
	// If no match, return ""
	if len(paths) <= 1 {
		return ""
	}
	return paths[0] + ".app"
}

func libraryDir() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return filepath.Join(usr.HomeDir, "Library"), nil
}

// Dir returns where to store config
func Dir(appName string) (string, error) {
	if appName == "" {
		return "", fmt.Errorf("No app name for dir")
	}
	libDir, err := libraryDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(libDir, "Application Support", appName), nil
}

// CacheDir returns where to store temporary files
func CacheDir(appName string) (string, error) {
	if appName == "" {
		return "", fmt.Errorf("No app name for dir")
	}
	return filepath.Join(os.TempDir(), appName), nil
}

// LogDir is where to log
func LogDir(appName string) (string, error) {
	libDir, err := libraryDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(libDir, "Logs"), nil
}

func (c config) osVersion() string {
	result, err := command.Exec("/usr/bin/sw_vers", []string{"-productVersion"}, 5*time.Second, c.log)
	if err != nil {
		c.log.Warningf("Error trying to determine OS version: %s (%s)", err, result.CombinedOutput())
		return ""
	}
	return strings.TrimSpace(result.Stdout.String())
}

func (c config) osArch() string {
	cmd := exec.Command("uname", "-m")
	var buf bytes.Buffer
	cmd.Stdout = &buf
	err := cmd.Run()
	if err != nil {
		return runtime.GOARCH
	}
	return buf.String()
}

func (c config) promptProgram() (command.Program, error) {
	destinationPath := c.destinationPath()
	if destinationPath == "" {
		return command.Program{}, fmt.Errorf("No destination path")
	}
	return command.Program{
		Path: filepath.Join(destinationPath, "Contents", "Resources", "KeybaseUpdater.app", "Contents", "MacOS", "Updater"),
	}, nil
}

func (c config) notifyProgram() string {
	// No notify program for Darwin
	return ""
}

func (c context) BeforeUpdatePrompt(update updater.Update, options updater.UpdateOptions) error {
	return nil
}

// UpdatePrompt is called when the user needs to accept an update
func (c context) UpdatePrompt(update updater.Update, options updater.UpdateOptions, promptOptions updater.UpdatePromptOptions) (*updater.UpdatePromptResponse, error) {
	promptProgram, err := c.config.promptProgram()
	if err != nil {
		return nil, err
	}
	return c.updatePrompt(promptProgram, update, options, promptOptions, time.Hour)
}

// PausedPrompt is called when the we can't update cause the app is in use.
// We return true if the use wants to cancel the update.
func (c context) PausedPrompt() bool {
	promptProgram, err := c.config.promptProgram()
	if err != nil {
		c.log.Warningf("Error trying to get prompt path: %s", err)
		return false
	}
	cancelUpdate, err := c.pausedPrompt(promptProgram, 5*time.Minute)
	if err != nil {
		c.log.Warningf("Error in paused prompt: %s", err)
		return false
	}
	return cancelUpdate
}

const serviceInBundlePath = "/Contents/SharedSupport/bin/keybase"
const kbfsInBundlePath = "/Contents/SharedSupport/bin/kbfs"

type processPaths struct {
	serviceProcPath string
	kbfsProcPath    string
	appPath         string
	appProcPath     string
}

func (c context) lookupProcessPaths() (p processPaths, _ error) {
	appPath := c.config.destinationPath() // "/Applications/Keybase.app"
	if appPath == "" {
		return p, fmt.Errorf("No app path")
	}
	appBundleName := filepath.Base(appPath) // "Keybase.app"

	p.appPath = appPath
	p.serviceProcPath = appBundleName + serviceInBundlePath
	p.kbfsProcPath = appBundleName + kbfsInBundlePath
	p.appProcPath = appBundleName + "/Contents/MacOS/"

	return p, nil
}

// stop will quit the app and any services
func (c context) stop() error {
	// Stop app
	appExitResult, appExitErr := command.Exec(c.config.keybasePath(), []string{"ctl", "app-exit"}, 30*time.Second, c.log)
	c.log.Infof("Stop output: %s", appExitResult.CombinedOutput())
	if appExitErr != nil {
		c.log.Warningf("Error requesting app exit: %s", appExitErr)
	}

	// Stop the redirector so it can be upgraded for all users.
	_, redirectorErr := command.Exec(c.config.keybasePath(), []string{"uninstall", "--components=redirector", fmt.Sprintf("--source-path=%s", sourcePath)}, time.Minute, c.log)
	if redirectorErr != nil {
		c.log.Warningf("Error stopping the redirector: %s", redirectorErr)
	}

	// Stop services
	servicesExitResult, servicesExitErr := command.Exec(c.config.keybasePath(), []string{"ctl", "stop", "--include=service,kbfs"}, 30*time.Second, c.log)
	c.log.Infof("Stop output: %s", servicesExitResult.CombinedOutput())
	if servicesExitErr != nil {
		c.log.Warningf("Error stopping services: %s", servicesExitErr)
	}

	paths, err := c.lookupProcessPaths()
	if err != nil {
		return err
	}

	// SIGKILL the app if it failed to exit (if it exited, then this doesn't do anything)
	c.log.Infof("Killing (if failed to exit) %s", paths.appProcPath)
	process.KillAll(process.NewMatcher(paths.appProcPath, process.PathContains, c.log), c.log)

	return nil
}

// AfterApply is called after an update is applied
func (c context) AfterApply(update updater.Update) error {
	if err := c.stop(); err != nil {
		c.log.Warningf("Error trying to stop: %s", err)
	}

	if err := c.start(10*time.Second, time.Second); err != nil {
		c.log.Warningf("Error trying to start the app: %s", err)
	}
	return nil
}

// Start the app.
// The wait is how log to wait for processes and the app to start before
// reporting that an error occurred.
func (c context) start(wait time.Duration, delay time.Duration) error {
	procPaths, err := c.lookupProcessPaths()
	if err != nil {
		return err
	}

	if err := OpenAppDarwin(procPaths.appPath, c.log); err != nil {
		c.log.Warningf("Error opening app: %s", err)
	}

	// Check to make sure processes started
	c.log.Debugf("Checking processes: %#v", procPaths)
	serviceProcErr := c.checkProcess(procPaths.serviceProcPath, wait, delay)
	kbfsProcErr := c.checkProcess(procPaths.kbfsProcPath, wait, delay)
	appProcErr := c.checkProcess(procPaths.appProcPath, wait, delay)

	return util.CombineErrors(serviceProcErr, kbfsProcErr, appProcErr)
}

func (c context) checkProcess(match string, wait time.Duration, delay time.Duration) error {
	matcher := process.NewMatcher(match, process.PathContains, c.log)
	procs, err := process.FindProcesses(matcher, wait, delay, c.log)
	if err != nil {
		return fmt.Errorf("Error checking on process (%s): %s", match, err)
	}
	if len(procs) == 0 {
		return fmt.Errorf("No process found for %s", match)
	}
	return nil
}

// OpenAppDarwin starts an app
func OpenAppDarwin(appPath string, log process.Log) error {
	return openAppDarwin("/usr/bin/open", appPath, time.Second, log)
}

func openAppDarwin(bin string, appPath string, retryDelay time.Duration, log process.Log) error {
	tryOpen := func() error {
		env := append(os.Environ(), "KEYBASE_RESTORE_UI=true", "KEYBASE_START_UI=hideWindow", "KEYBASE_OPEN_FROM=updater")
		result, err := command.ExecWithEnv(bin, []string{appPath}, env, time.Minute, log)
		if err != nil {
			return fmt.Errorf("Open error: %s; %s", err, result.CombinedOutput())
		}
		return nil
	}
	// We need to try 10 times because Gatekeeper has some issues, for example,
	// http://www.openradar.me/23614087
	var err error
	for i := 0; i < 10; i++ {
		err = tryOpen()
		if err == nil {
			break
		}
		log.Errorf("Open error (trying again in %s): %s", retryDelay, err)
		time.Sleep(retryDelay)
	}
	return err
}

func (c context) check(sourcePath string, destinationPath string) error {
	// Check to make sure the update source path is a real directory
	ok, err := util.IsDirReal(sourcePath)
	if err != nil {
		return err
	}
	if !ok {
		return fmt.Errorf("Source path isn't a directory")
	}
	return nil
}

func (c context) apply(localPath string, destinationPath string, tmpDir string) error {
	// The file name we unzip over should match the (base) file in the destination path
	filename := filepath.Base(destinationPath)
	return util.UnzipOver(localPath, filename, destinationPath, c.check, tmpDir, c.log)
}

func (c context) Apply(update updater.Update, options updater.UpdateOptions, tmpDir string) error {
	if update.Asset == nil {
		return fmt.Errorf("No asset")
	}
	localPath := update.Asset.LocalPath
	destinationPath := options.DestinationPath

	err := c.apply(localPath, destinationPath, tmpDir)
	switch err := err.(type) {
	case nil:
	case *os.LinkError:
		if err.Op == "rename" && err.Old == "/Applications/Keybase.app" {
			c.log.Infof("The error was a problem renaming (moving) the app, let's trying installing the app via keybase install --components=app which has more privileges")

			// Unzip and get source path
			unzipPath, err := util.UnzipPath(localPath, c.log)
			defer util.RemoveFileAtPath(unzipPath)
			if err != nil {
				return err
			}
			sourcePath := filepath.Join(unzipPath, filepath.Base(destinationPath))

			_, installErr := command.Exec(c.config.keybasePath(), []string{"install", "--components=app", fmt.Sprintf("--source-path=%s", sourcePath)}, time.Minute, c.log)
			if installErr != nil {
				c.log.Errorf("Error trying to install the app (privileged): %s", installErr)
				return installErr
			}
		} else {
			return err
		}
	default:
		return err
	}

	// Update spotlight
	c.log.Debugf("Updating spotlight: %s", destinationPath)
	spotlightResult, spotLightErr := command.Exec("/usr/bin/mdimport", []string{destinationPath}, 20*time.Second, c.log)
	if spotLightErr != nil {
		c.log.Warningf("Error trying to update spotlight: %s, (%s)", spotLightErr, spotlightResult.CombinedOutput())
	}

	// Remove quantantine (if any)
	c.log.Debugf("Remove quarantine: %s", destinationPath)
	quarantineResult, quarantineErr := command.Exec("/usr/bin/xattr", []string{"-d", "com.apple.quarantine", destinationPath}, 20*time.Second, c.log)
	if quarantineErr != nil {
		c.log.Warningf("Error trying to remove quarantine: %s, (%s)", quarantineErr, quarantineResult.CombinedOutput())
	}

	return nil
}
<commit_msg>osx: fix compile for redirector uninstall<commit_after>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/kardianos/osext"
	"github.com/keybase/go-updater"
	"github.com/keybase/go-updater/command"
	"github.com/keybase/go-updater/process"
	"github.com/keybase/go-updater/util"
)

// execPath returns the app bundle path where this executable is located
func (c config) execPath() string {
	path, err := osext.Executable()
	if err != nil {
		c.log.Warningf("Error trying to determine our executable path: %s", err)
		return ""
	}
	return path
}

// destinationPath returns the app bundle path where this executable is located
func (c config) destinationPath() string {
	return appBundleForPath(c.execPath())
}

func appBundleForPath(path string) string {
	if path == "" {
		return ""
	}
	paths := strings.SplitN(path, ".app", 2)
	// If no match, return ""
	if len(paths) <= 1 {
		return ""
	}
	return paths[0] + ".app"
}

func libraryDir() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return filepath.Join(usr.HomeDir, "Library"), nil
}

// Dir returns where to store config
func Dir(appName string) (string, error) {
	if appName == "" {
		return "", fmt.Errorf("No app name for dir")
	}
	libDir, err := libraryDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(libDir, "Application Support", appName), nil
}

// CacheDir returns where to store temporary files
func CacheDir(appName string) (string, error) {
	if appName == "" {
		return "", fmt.Errorf("No app name for dir")
	}
	return filepath.Join(os.TempDir(), appName), nil
}

// LogDir is where to log
func LogDir(appName string) (string, error) {
	libDir, err := libraryDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(libDir, "Logs"), nil
}

func (c config) osVersion() string {
	result, err := command.Exec("/usr/bin/sw_vers", []string{"-productVersion"}, 5*time.Second, c.log)
	if err != nil {
		c.log.Warningf("Error trying to determine OS version: %s (%s)", err, result.CombinedOutput())
		return ""
	}
	return strings.TrimSpace(result.Stdout.String())
}

func (c config) osArch() string {
	cmd := exec.Command("uname", "-m")
	var buf bytes.Buffer
	cmd.Stdout = &buf
	err := cmd.Run()
	if err != nil {
		return runtime.GOARCH
	}
	return buf.String()
}

func (c config) promptProgram() (command.Program, error) {
	destinationPath := c.destinationPath()
	if destinationPath == "" {
		return command.Program{}, fmt.Errorf("No destination path")
	}
	return command.Program{
		Path: filepath.Join(destinationPath, "Contents", "Resources", "KeybaseUpdater.app", "Contents", "MacOS", "Updater"),
	}, nil
}

func (c config) notifyProgram() string {
	// No notify program for Darwin
	return ""
}

func (c context) BeforeUpdatePrompt(update updater.Update, options updater.UpdateOptions) error {
	return nil
}

// UpdatePrompt is called when the user needs to accept an update
func (c context) UpdatePrompt(update updater.Update, options updater.UpdateOptions, promptOptions updater.UpdatePromptOptions) (*updater.UpdatePromptResponse, error) {
	promptProgram, err := c.config.promptProgram()
	if err != nil {
		return nil, err
	}
	return c.updatePrompt(promptProgram, update, options, promptOptions, time.Hour)
}

// PausedPrompt is called when the we can't update cause the app is in use.
// We return true if the use wants to cancel the update.
func (c context) PausedPrompt() bool {
	promptProgram, err := c.config.promptProgram()
	if err != nil {
		c.log.Warningf("Error trying to get prompt path: %s", err)
		return false
	}
	cancelUpdate, err := c.pausedPrompt(promptProgram, 5*time.Minute)
	if err != nil {
		c.log.Warningf("Error in paused prompt: %s", err)
		return false
	}
	return cancelUpdate
}

const serviceInBundlePath = "/Contents/SharedSupport/bin/keybase"
const kbfsInBundlePath = "/Contents/SharedSupport/bin/kbfs"

type processPaths struct {
	serviceProcPath string
	kbfsProcPath    string
	appPath         string
	appProcPath     string
}

func (c context) lookupProcessPaths() (p processPaths, _ error) {
	appPath := c.config.destinationPath() // "/Applications/Keybase.app"
	if appPath == "" {
		return p, fmt.Errorf("No app path")
	}
	appBundleName := filepath.Base(appPath) // "Keybase.app"

	p.appPath = appPath
	p.serviceProcPath = appBundleName + serviceInBundlePath
	p.kbfsProcPath = appBundleName + kbfsInBundlePath
	p.appProcPath = appBundleName + "/Contents/MacOS/"

	return p, nil
}

// stop will quit the app and any services
func (c context) stop() error {
	// Stop app
	appExitResult, appExitErr := command.Exec(c.config.keybasePath(), []string{"ctl", "app-exit"}, 30*time.Second, c.log)
	c.log.Infof("Stop output: %s", appExitResult.CombinedOutput())
	if appExitErr != nil {
		c.log.Warningf("Error requesting app exit: %s", appExitErr)
	}

	// Stop the redirector so it can be upgraded for all users.
	_, redirectorErr := command.Exec(c.config.keybasePath(), []string{"uninstall", "--components=redirector"}, time.Minute, c.log)
	if redirectorErr != nil {
		c.log.Warningf("Error stopping the redirector: %s", redirectorErr)
	}

	// Stop services
	servicesExitResult, servicesExitErr := command.Exec(c.config.keybasePath(), []string{"ctl", "stop", "--include=service,kbfs"}, 30*time.Second, c.log)
	c.log.Infof("Stop output: %s", servicesExitResult.CombinedOutput())
	if servicesExitErr != nil {
		c.log.Warningf("Error stopping services: %s", servicesExitErr)
	}

	paths, err := c.lookupProcessPaths()
	if err != nil {
		return err
	}

	// SIGKILL the app if it failed to exit (if it exited, then this doesn't do anything)
	c.log.Infof("Killing (if failed to exit) %s", paths.appProcPath)
	process.KillAll(process.NewMatcher(paths.appProcPath, process.PathContains, c.log), c.log)

	return nil
}

// AfterApply is called after an update is applied
func (c context) AfterApply(update updater.Update) error {
	if err := c.stop(); err != nil {
		c.log.Warningf("Error trying to stop: %s", err)
	}

	if err := c.start(10*time.Second, time.Second); err != nil {
		c.log.Warningf("Error trying to start the app: %s", err)
	}
	return nil
}

// Start the app.
// The wait is how log to wait for processes and the app to start before
// reporting that an error occurred.
func (c context) start(wait time.Duration, delay time.Duration) error {
	procPaths, err := c.lookupProcessPaths()
	if err != nil {
		return err
	}

	if err := OpenAppDarwin(procPaths.appPath, c.log); err != nil {
		c.log.Warningf("Error opening app: %s", err)
	}

	// Check to make sure processes started
	c.log.Debugf("Checking processes: %#v", procPaths)
	serviceProcErr := c.checkProcess(procPaths.serviceProcPath, wait, delay)
	kbfsProcErr := c.checkProcess(procPaths.kbfsProcPath, wait, delay)
	appProcErr := c.checkProcess(procPaths.appProcPath, wait, delay)

	return util.CombineErrors(serviceProcErr, kbfsProcErr, appProcErr)
}

func (c context) checkProcess(match string, wait time.Duration, delay time.Duration) error {
	matcher := process.NewMatcher(match, process.PathContains, c.log)
	procs, err := process.FindProcesses(matcher, wait, delay, c.log)
	if err != nil {
		return fmt.Errorf("Error checking on process (%s): %s", match, err)
	}
	if len(procs) == 0 {
		return fmt.Errorf("No process found for %s", match)
	}
	return nil
}

// OpenAppDarwin starts an app
func OpenAppDarwin(appPath string, log process.Log) error {
	return openAppDarwin("/usr/bin/open", appPath, time.Second, log)
}

func openAppDarwin(bin string, appPath string, retryDelay time.Duration, log process.Log) error {
	tryOpen := func() error {
		env := append(os.Environ(), "KEYBASE_RESTORE_UI=true", "KEYBASE_START_UI=hideWindow", "KEYBASE_OPEN_FROM=updater")
		result, err := command.ExecWithEnv(bin, []string{appPath}, env, time.Minute, log)
		if err != nil {
			return fmt.Errorf("Open error: %s; %s", err, result.CombinedOutput())
		}
		return nil
	}
	// We need to try 10 times because Gatekeeper has some issues, for example,
	// http://www.openradar.me/23614087
	var err error
	for i := 0; i < 10; i++ {
		err = tryOpen()
		if err == nil {
			break
		}
		log.Errorf("Open error (trying again in %s): %s", retryDelay, err)
		time.Sleep(retryDelay)
	}
	return err
}

func (c context) check(sourcePath string, destinationPath string) error {
	// Check to make sure the update source path is a real directory
	ok, err := util.IsDirReal(sourcePath)
	if err != nil {
		return err
	}
	if !ok {
		return fmt.Errorf("Source path isn't a directory")
	}
	return nil
}

func (c context) apply(localPath string, destinationPath string, tmpDir string) error {
	// The file name we unzip over should match the (base) file in the destination path
	filename := filepath.Base(destinationPath)
	return util.UnzipOver(localPath, filename, destinationPath, c.check, tmpDir, c.log)
}

func (c context) Apply(update updater.Update, options updater.UpdateOptions, tmpDir string) error {
	if update.Asset == nil {
		return fmt.Errorf("No asset")
	}
	localPath := update.Asset.LocalPath
	destinationPath := options.DestinationPath

	err := c.apply(localPath, destinationPath, tmpDir)
	switch err := err.(type) {
	case nil:
	case *os.LinkError:
		if err.Op == "rename" && err.Old == "/Applications/Keybase.app" {
			c.log.Infof("The error was a problem renaming (moving) the app, let's trying installing the app via keybase install --components=app which has more privileges")

			// Unzip and get source path
			unzipPath, err := util.UnzipPath(localPath, c.log)
			defer util.RemoveFileAtPath(unzipPath)
			if err != nil {
				return err
			}
			sourcePath := filepath.Join(unzipPath, filepath.Base(destinationPath))

			_, installErr := command.Exec(c.config.keybasePath(), []string{"install", "--components=app", fmt.Sprintf("--source-path=%s", sourcePath)}, time.Minute, c.log)
			if installErr != nil {
				c.log.Errorf("Error trying to install the app (privileged): %s", installErr)
				return installErr
			}
		} else {
			return err
		}
	default:
		return err
	}

	// Update spotlight
	c.log.Debugf("Updating spotlight: %s", destinationPath)
	spotlightResult, spotLightErr := command.Exec("/usr/bin/mdimport", []string{destinationPath}, 20*time.Second, c.log)
	if spotLightErr != nil {
		c.log.Warningf("Error trying to update spotlight: %s, (%s)", spotLightErr, spotlightResult.CombinedOutput())
	}

	// Remove quantantine (if any)
	c.log.Debugf("Remove quarantine: %s", destinationPath)
	quarantineResult, quarantineErr := command.Exec("/usr/bin/xattr", []string{"-d", "com.apple.quarantine", destinationPath}, 20*time.Second, c.log)
	if quarantineErr != nil {
		c.log.Warningf("Error trying to remove quarantine: %s, (%s)", quarantineErr, quarantineResult.CombinedOutput())
	}

	return nil
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceGoogleStorageBucket_basic(t *testing.T) {
	t.Parallel()

	bucket := "tf-bucket-" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		CheckDestroy: testAccStorageBucketDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceGoogleStorageBucketConfig(bucket),
				Check: resource.ComposeTestCheckFunc(
					checkDataSourceStateMatchesResourceStateWithIgnores("data.google_storage_bucket.bar", "google_storage_bucket.foo", map[string]struct{}{"force_destroy": {}}),
				),
			},
		},
	})
}

func testAccDataSourceGoogleStorageBucketConfig(bucketName string) string {
	return fmt.Sprintf(`
resource "google_storage_bucket" "foo" {
  name               = "%s"
}

data "google_storage_bucket" "bar" {
  name = google_storage_bucket.foo.name
  depends_on = [
    google_storage_bucket.foo,
  ]
}
`, bucketName)
}
<commit_msg>Run gofmt on storage bucket datasource test file (#5255)<commit_after>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceGoogleStorageBucket_basic(t *testing.T) {
	t.Parallel()

	bucket := "tf-bucket-" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccStorageBucketDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceGoogleStorageBucketConfig(bucket),
				Check: resource.ComposeTestCheckFunc(
					checkDataSourceStateMatchesResourceStateWithIgnores("data.google_storage_bucket.bar", "google_storage_bucket.foo", map[string]struct{}{"force_destroy": {}}),
				),
			},
		},
	})
}

func testAccDataSourceGoogleStorageBucketConfig(bucketName string) string {
	return fmt.Sprintf(`
resource "google_storage_bucket" "foo" {
  name               = "%s"
}

data "google_storage_bucket" "bar" {
  name = google_storage_bucket.foo.name
  depends_on = [
    google_storage_bucket.foo,
  ]
}
`, bucketName)
}
<|endoftext|>


<commit_before>package devmapper

import (
	"fmt"
	"os"
	"path"
	"github.com/dotcloud/docker/archive"
)

// Placeholder interfaces, to be replaced
// at integration.

type Image interface {
	ID() string
	Parent() (Image, error)
	Path() string
}

type Change interface {

}

// End of placeholder interfaces.

type DMBackend struct {
	*DeviceSet
	home string
}

func Init(home string) (*DMBackend, error) {
	b := &DMBackend{
		DeviceSet: NewDeviceSet(home),
		home: home,
	}
	if err := b.DeviceSet.ensureInit(); err != nil {
		return nil, err
	}
	return b, nil
}

func (b *DMBackend) Cleanup() error {
	return b.DeviceSet.Shutdown()
}

func (b *DMBackend) OnCreate(img Image, layer archive.Archive) error {
	// Determine the source of the snapshot (parent id or init device)
	var parentID string
	if parent, err := img.Parent(); err != nil {
		return err
	} else if parent != nil {
		parentID = parent.ID()
	}
	// Create the device for this image by snapshotting source
	if err := b.DeviceSet.AddDevice(img.ID(), parentID); err != nil {
		return err
	}
	// Mount the device in rootfs
	mp := b.mountpoint(img.ID())
	if err := os.MkdirAll(mp, 0700); err != nil {
		return err
	}
	if err := b.DeviceSet.MountDevice(img.ID(), mp, false); err != nil {
		return err
	}
	// Apply the layer as a diff
	if layer != nil {
		if err := archive.ApplyLayer(mp, layer); err != nil {
			return err
		}
	}
	return nil
}

func (b *DMBackend) mountpoint(id string) string {
	if b.home == "" {
		return ""
	}
	return path.Join(b.home, "mnt", id)
}

func (b *DMBackend) Changes(img *Image, dest string) ([]Change, error) {
	return nil, fmt.Errorf("Not implemented")
}

func (b *DMBackend) Layer(img *Image, dest string) (archive.Archive, error) {
	return nil, fmt.Errorf("Not implemented")
}
<commit_msg>devmapper: implement OnRemove<commit_after>package devmapper

import (
	"fmt"
	"os"
	"path"
	"github.com/dotcloud/docker/archive"
)

// Placeholder interfaces, to be replaced
// at integration.

type Image interface {
	ID() string
	Parent() (Image, error)
	Path() string
}

type Change interface {

}

// End of placeholder interfaces.

type DMBackend struct {
	*DeviceSet
	home string
}

func Init(home string) (*DMBackend, error) {
	b := &DMBackend{
		DeviceSet: NewDeviceSet(home),
		home: home,
	}
	if err := b.DeviceSet.ensureInit(); err != nil {
		return nil, err
	}
	return b, nil
}

func (b *DMBackend) Cleanup() error {
	return b.DeviceSet.Shutdown()
}

func (b *DMBackend) OnCreate(img Image, layer archive.Archive) error {
	// Determine the source of the snapshot (parent id or init device)
	var parentID string
	if parent, err := img.Parent(); err != nil {
		return err
	} else if parent != nil {
		parentID = parent.ID()
	}
	// Create the device for this image by snapshotting source
	if err := b.DeviceSet.AddDevice(img.ID(), parentID); err != nil {
		return err
	}
	// Mount the device in rootfs
	mp := b.mountpoint(img.ID())
	if err := os.MkdirAll(mp, 0700); err != nil {
		return err
	}
	if err := b.DeviceSet.MountDevice(img.ID(), mp, false); err != nil {
		return err
	}
	// Apply the layer as a diff
	if layer != nil {
		if err := archive.ApplyLayer(mp, layer); err != nil {
			return err
		}
	}
	return nil
}

func (b *DMBackend) OnRemove(img Image) error {
	id := img.ID()
	if err := b.DeviceSet.RemoveDevice(id); err != nil {
		return fmt.Errorf("Unable to remove device for %v: %v", id, err)
	}
	return nil
}

func (b *DMBackend) mountpoint(id string) string {
	if b.home == "" {
		return ""
	}
	return path.Join(b.home, "mnt", id)
}

func (b *DMBackend) Changes(img *Image, dest string) ([]Change, error) {
	return nil, fmt.Errorf("Not implemented")
}

func (b *DMBackend) Layer(img *Image, dest string) (archive.Archive, error) {
	return nil, fmt.Errorf("Not implemented")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/jmervine/env"
)

func init() {
	// set default port if not set
	env.GetOrSetInt("PORT", 3000)

	log.SetOutput(os.Stdout)
	log.SetFlags(0)
}

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		begin := time.Now()
		status := http.StatusOK

		defer func() {
			logPrefix := fmt.Sprintf("at=main on=http.HandleFunc method=%s path=%s", r.Method, r.URL.Path)
			log.Printf("%s status=%d took=%v\n", logPrefix, status, time.Since(begin))
			if env.GetBool("VERBOSE") {
				log.Printf("%s headers:\n%s", r.Header)
				body, err := ioutil.ReadAll(r.Body)
				if err == nil {
					log.Printf("%s body:\n%s", string(body))
				}
			}
		}()

		statusHeader := r.Header.Get("X-HTTP-Status")
		if statusHeader != "" {
			i, e := strconv.ParseInt(statusHeader, 10, 16)
			if e == nil {
				status = int(i)
			} else {
				status = 500
			}
		}

		http.Error(w, fmt.Sprintf("%d %s", status, http.StatusText(status)), status)
	})

	log.Printf("at=main on=startup addr=%s port=%s\n", env.Get("ADDR"), env.Get("PORT"))
	log.Fatal(http.ListenAndServe(env.Get("ADDR")+":"+env.Get("PORT"), nil))
}
<commit_msg>Updating logging and default bind<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/jmervine/env"
)

func init() {
	// set default port if not set
	env.GetOrSetInt("PORT", 3000)
	env.GetOrSetString("ADDR", "0.0.0.0")

	app := os.Getenv("APP_NAME")
	if app == "" {
		app = "noop-server"
	}

	log.SetPrefix("app=" + app + " ")
	log.SetOutput(os.Stdout)
	log.SetFlags(0)
}

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		begin := time.Now()
		status := http.StatusOK

		defer func() {
			logPrefix := fmt.Sprintf("at=main on=http.HandleFunc method=%s path=%s", r.Method, r.URL.Path)
			log.Printf("%s status=%d took=%v\n", logPrefix, status, time.Since(begin))
			if env.GetBool("VERBOSE") {
				log.Printf("%s headers:\n%s", r.Header)
				body, err := ioutil.ReadAll(r.Body)
				if err == nil {
					log.Printf("%s body:\n%s", string(body))
				}
			}
		}()

		statusHeader := r.Header.Get("X-HTTP-Status")
		if statusHeader != "" {
			i, e := strconv.ParseInt(statusHeader, 10, 16)
			if e == nil {
				status = int(i)
			} else {
				status = 500
			}
		}

		http.Error(w, fmt.Sprintf("%d %s", status, http.StatusText(status)), status)
	})

	log.Printf("at=main on=startup addr=%s port=%s\n", env.Get("ADDR"), env.Get("PORT"))
	log.Fatal(http.ListenAndServe(env.Get("ADDR")+":"+env.Get("PORT"), nil))
}
<|endoftext|>


<commit_before>package message

import (
	"DNA/common/log"
	. "DNA/net/protocol"
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
)

type Messager interface {
	Verify([]byte) error
	Serialization() ([]byte, error)
	Deserialization([]byte) error
	Handle(Noder) error
}

// The network communication message header
type msgHdr struct {
	Magic uint32
	//ID	 uint64
	CMD      [MSGCMDLEN]byte // The message type
	Length   uint32
	Checksum [CHECKSUMLEN]byte
}

// The message body and header
type msgCont struct {
	hdr msgHdr
	p   interface{}
}

type varStr struct {
	len uint
	buf []byte
}

type filteradd struct {
	msgHdr
	//TBD
}

type filterclear struct {
	msgHdr
	//TBD
}

type filterload struct {
	msgHdr
	//TBD
}

// Alloc different message stucture
// @t the message name or type
// @len the message length only valid for varible length structure
//
// Return:
// @messager the messager interface
// @error  error code
// FixMe fix the ugly multiple return.
func AllocMsg(t string, length int) Messager {
	switch t {
	case "msgheader":
		var msg msgHdr
		return &msg
	case "version":
		var msg version
		// TODO fill the header and type
		copy(msg.Hdr.CMD[0:len(t)], t)
		return &msg
	case "verack":
		var msg verACK
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "getheaders":
		var msg headersReq
		// TODO fill the header and type
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "headers":
		var msg blkHeader
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "getaddr":
		var msg addrReq
		copy(msg.Hdr.CMD[0:len(t)], t)
		return &msg
	case "addr":
		var msg addr
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "inv":
		var msg Inv
		copy(msg.Hdr.CMD[0:len(t)], t)
		// the 1 is the inv type lenght
		msg.P.Blk = make([]byte, length-MSGHDRLEN-1)
		return &msg
	case "getdata":
		var msg dataReq
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "block":
		var msg block
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "tx":
		var msg trn
		copy(msg.msgHdr.CMD[0:len(t)], t)
		//if (message.Payload.Length <= 1024 * 1024)
		//OnInventoryReceived(Transaction.DeserializeFrom(message.Payload));
		return &msg
	case "consensus":
		var msg consensus
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filteradd":
		var msg filteradd
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filterclear":
		var msg filterclear
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filterload":
		var msg filterload
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "getblocks":
		var msg blocksReq
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "txnpool":
		var msg txnPool
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "alert":
		errors.New("Not supported message type")
		return nil
	case "merkleblock":
		errors.New("Not supported message type")
		return nil
	case "notfound":
		errors.New("Not supported message type")
		return nil
	case "ping":
		errors.New("Not supported message type")
		return nil
	case "pong":
		errors.New("Not supported message type")
		return nil
	case "reject":
		errors.New("Not supported message type")
		return nil
	default:
		errors.New("Unknown message type")
		return nil
	}
}

func MsgType(buf []byte) (string, error) {
	cmd := buf[CMDOFFSET : CMDOFFSET+MSGCMDLEN]
	n := bytes.IndexByte(cmd, 0)
	if n < 0 || n >= MSGCMDLEN {
		return "", errors.New("Unexpected length of CMD command")
	}
	s := string(cmd[:n])
	return s, nil
}

// TODO combine all of message alloc in one function via interface
func NewMsg(t string, n Noder) ([]byte, error) {
	switch t {
	case "version":
		return NewVersion(n)
	case "verack":
		return NewVerack()
	case "getheaders":
		return NewHeadersReq(n)
	case "getaddr":
		return newGetAddr()

	default:
		return nil, errors.New("Unknown message type")
	}
}

// FIXME the length exceed int32 case?
func HandleNodeMsg(node Noder, buf []byte, len int) error {
	if len < MSGHDRLEN {
		log.Warn("Unexpected size of received message")
		return errors.New("Unexpected size of received message")
	}

	str := hex.EncodeToString(buf[:len])
	log.Debug("Received data len: ", len, "\n", str)

	s, err := MsgType(buf)
	if err != nil {
		fmt.Println(err.Error())
		return err
	}

	msg := AllocMsg(s, len)
	if msg == nil {
		fmt.Println(err.Error())
		return err
	}
	// Todo attach a ndoe pointer to each message
	// Todo drop the message when verify/deseria packet error
	msg.Deserialization(buf[:len])
	msg.Verify(buf[MSGHDRLEN:len])

	return msg.Handle(node)
}

func magicVerify(magic uint32) bool {
	if magic != NETMAGIC {
		return false
	}
	return true
}

func PayloadLen(buf []byte) int {
	var h msgHdr
	h.Deserialization(buf)
	return int(h.Length)
}

func checkSum(p []byte) []byte {
	t := sha256.Sum256(p)
	s := sha256.Sum256(t[:])

	// Currently we only need the front 4 bytes as checksum
	return s[:CHECKSUMLEN]
}

func reverse(input []byte) []byte {
	if len(input) == 0 {
		return input
	}
	return append(reverse(input[1:]), input[0])
}

func (hdr *msgHdr) init(cmd string, checksum []byte, length uint32) {
	hdr.Magic = NETMAGIC
	copy(hdr.CMD[0:uint32(len(cmd))], cmd)
	copy(hdr.Checksum[:], checksum[:CHECKSUMLEN])
	hdr.Length = length
	//hdr.ID = id
}

// Verify the message header information
// @p payload of the message
func (hdr msgHdr) Verify(buf []byte) error {
	if magicVerify(hdr.Magic) == false {
		log.Warn(fmt.Sprintf("Unmatched magic number 0x%0x", hdr.Magic))
		return errors.New("Unmatched magic number")
	}
	checkSum := checkSum(buf)
	if bytes.Equal(hdr.Checksum[:], checkSum[:]) == false {
		str1 := hex.EncodeToString(hdr.Checksum[:])
		str2 := hex.EncodeToString(checkSum[:])
		log.Warn(fmt.Sprintf("Message Checksum error, Received checksum %s Wanted checksum: %s",
			str1, str2))
		return errors.New("Message Checksum error")
	}

	return nil
}

func (msg *msgHdr) Deserialization(p []byte) error {

	buf := bytes.NewBuffer(p[0:MSGHDRLEN])
	err := binary.Read(buf, binary.LittleEndian, msg)
	return err
}

// FIXME how to avoid duplicate serial/deserial function as
// most of them are the same
func (hdr msgHdr) Serialization() ([]byte, error) {
	var buf bytes.Buffer
	err := binary.Write(&buf, binary.LittleEndian, hdr)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), err
}

func (hdr msgHdr) Handle(n Noder) error {
	log.Trace()
	// TBD
	return nil
}
<commit_msg>Won't handle consensus message untill block finish sync<commit_after>package message

import (
	"DNA/common"
	"DNA/common/log"
	"DNA/core/ledger"
	. "DNA/net/protocol"
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
)

type Messager interface {
	Verify([]byte) error
	Serialization() ([]byte, error)
	Deserialization([]byte) error
	Handle(Noder) error
}

// The network communication message header
type msgHdr struct {
	Magic uint32
	//ID	 uint64
	CMD      [MSGCMDLEN]byte // The message type
	Length   uint32
	Checksum [CHECKSUMLEN]byte
}

// The message body and header
type msgCont struct {
	hdr msgHdr
	p   interface{}
}

type varStr struct {
	len uint
	buf []byte
}

type filteradd struct {
	msgHdr
	//TBD
}

type filterclear struct {
	msgHdr
	//TBD
}

type filterload struct {
	msgHdr
	//TBD
}

// Alloc different message stucture
// @t the message name or type
// @len the message length only valid for varible length structure
//
// Return:
// @messager the messager interface
// @error  error code
// FixMe fix the ugly multiple return.
func AllocMsg(t string, length int) Messager {
	switch t {
	case "msgheader":
		var msg msgHdr
		return &msg
	case "version":
		var msg version
		// TODO fill the header and type
		copy(msg.Hdr.CMD[0:len(t)], t)
		return &msg
	case "verack":
		var msg verACK
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "getheaders":
		var msg headersReq
		// TODO fill the header and type
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "headers":
		var msg blkHeader
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "getaddr":
		var msg addrReq
		copy(msg.Hdr.CMD[0:len(t)], t)
		return &msg
	case "addr":
		var msg addr
		copy(msg.hdr.CMD[0:len(t)], t)
		return &msg
	case "inv":
		var msg Inv
		copy(msg.Hdr.CMD[0:len(t)], t)
		// the 1 is the inv type lenght
		msg.P.Blk = make([]byte, length-MSGHDRLEN-1)
		return &msg
	case "getdata":
		var msg dataReq
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "block":
		var msg block
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "tx":
		var msg trn
		copy(msg.msgHdr.CMD[0:len(t)], t)
		//if (message.Payload.Length <= 1024 * 1024)
		//OnInventoryReceived(Transaction.DeserializeFrom(message.Payload));
		return &msg
	case "consensus":
		var msg consensus
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filteradd":
		var msg filteradd
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filterclear":
		var msg filterclear
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "filterload":
		var msg filterload
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "getblocks":
		var msg blocksReq
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "txnpool":
		var msg txnPool
		copy(msg.msgHdr.CMD[0:len(t)], t)
		return &msg
	case "alert":
		errors.New("Not supported message type")
		return nil
	case "merkleblock":
		errors.New("Not supported message type")
		return nil
	case "notfound":
		errors.New("Not supported message type")
		return nil
	case "ping":
		errors.New("Not supported message type")
		return nil
	case "pong":
		errors.New("Not supported message type")
		return nil
	case "reject":
		errors.New("Not supported message type")
		return nil
	default:
		errors.New("Unknown message type")
		return nil
	}
}

func MsgType(buf []byte) (string, error) {
	cmd := buf[CMDOFFSET : CMDOFFSET+MSGCMDLEN]
	n := bytes.IndexByte(cmd, 0)
	if n < 0 || n >= MSGCMDLEN {
		return "", errors.New("Unexpected length of CMD command")
	}
	s := string(cmd[:n])
	return s, nil
}

// TODO combine all of message alloc in one function via interface
func NewMsg(t string, n Noder) ([]byte, error) {
	switch t {
	case "version":
		return NewVersion(n)
	case "verack":
		return NewVerack()
	case "getheaders":
		return NewHeadersReq(n)
	case "getaddr":
		return newGetAddr()

	default:
		return nil, errors.New("Unknown message type")
	}
}

// FIXME the length exceed int32 case?
func HandleNodeMsg(node Noder, buf []byte, len int) error {
	if len < MSGHDRLEN {
		log.Warn("Unexpected size of received message")
		return errors.New("Unexpected size of received message")
	}

	str := hex.EncodeToString(buf[:len])
	log.Debug("Received data len: ", len, "\n", str)

	s, err := MsgType(buf)
	if err != nil {
		fmt.Println(err.Error())
		return err
	}

	heights, _ := node.LocalNode().GetNeighborHeights()
	if common.CompareHeight(uint64(ledger.DefaultLedger.Blockchain.BlockHeight), heights) == false {
		if strings.Compare(s, "consensus") == 0 {
			log.Error("sync up block havn't finished, height is ", uint64(ledger.DefaultLedger.Blockchain.BlockHeight), " ,others height are: ", heights)
			return errors.New("sync up block havn't finished")
		}
	}
	msg := AllocMsg(s, len)
	if msg == nil {
		fmt.Println(err.Error())
		return err
	}
	// Todo attach a ndoe pointer to each message
	// Todo drop the message when verify/deseria packet error
	msg.Deserialization(buf[:len])
	msg.Verify(buf[MSGHDRLEN:len])

	return msg.Handle(node)
}

func magicVerify(magic uint32) bool {
	if magic != NETMAGIC {
		return false
	}
	return true
}

func PayloadLen(buf []byte) int {
	var h msgHdr
	h.Deserialization(buf)
	return int(h.Length)
}

func checkSum(p []byte) []byte {
	t := sha256.Sum256(p)
	s := sha256.Sum256(t[:])

	// Currently we only need the front 4 bytes as checksum
	return s[:CHECKSUMLEN]
}

func reverse(input []byte) []byte {
	if len(input) == 0 {
		return input
	}
	return append(reverse(input[1:]), input[0])
}

func (hdr *msgHdr) init(cmd string, checksum []byte, length uint32) {
	hdr.Magic = NETMAGIC
	copy(hdr.CMD[0:uint32(len(cmd))], cmd)
	copy(hdr.Checksum[:], checksum[:CHECKSUMLEN])
	hdr.Length = length
	//hdr.ID = id
}

// Verify the message header information
// @p payload of the message
func (hdr msgHdr) Verify(buf []byte) error {
	if magicVerify(hdr.Magic) == false {
		log.Warn(fmt.Sprintf("Unmatched magic number 0x%0x", hdr.Magic))
		return errors.New("Unmatched magic number")
	}
	checkSum := checkSum(buf)
	if bytes.Equal(hdr.Checksum[:], checkSum[:]) == false {
		str1 := hex.EncodeToString(hdr.Checksum[:])
		str2 := hex.EncodeToString(checkSum[:])
		log.Warn(fmt.Sprintf("Message Checksum error, Received checksum %s Wanted checksum: %s",
			str1, str2))
		return errors.New("Message Checksum error")
	}

	return nil
}

func (msg *msgHdr) Deserialization(p []byte) error {

	buf := bytes.NewBuffer(p[0:MSGHDRLEN])
	err := binary.Read(buf, binary.LittleEndian, msg)
	return err
}

// FIXME how to avoid duplicate serial/deserial function as
// most of them are the same
func (hdr msgHdr) Serialization() ([]byte, error) {
	var buf bytes.Buffer
	err := binary.Write(&buf, binary.LittleEndian, hdr)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), err
}

func (hdr msgHdr) Handle(n Noder) error {
	log.Trace()
	// TBD
	return nil
}
<|endoftext|>


<commit_before>// Copyright ©2015 The gonum 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 network

import (
	"math"

	"github.com/gonum/graph"
	"github.com/gonum/graph/internal"
	"github.com/gonum/graph/path"
)

// Betweenness returns the non-zero betweenness centrality for nodes in the unweighted graph g.
//
//  C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st})
//
// where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t,
// and the subset of those paths containing v respectively.
func Betweenness(g graph.Graph) map[int]float64 {
	// Brandes' algorithm for finding betweenness centrality for nodes in
	// and unweighted graph:
	//
	// http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf

	// TODO(kortschak): Consider using the parallel algorithm when
	// GOMAXPROCS != 1.
	//
	// http://htor.inf.ethz.ch/publications/img/edmonds-hoefler-lumsdaine-bc.pdf

	// Also note special case for sparse networks:
	// http://wwwold.iit.cnr.it/staff/marco.pellegrini/papiri/asonam-final.pdf

	var (
		cb = make(map[int]float64)

		nodes = g.Nodes()
		stack internal.NodeStack
		p     = make(map[int][]graph.Node, len(nodes))
		sigma = make(map[int]float64, len(nodes))
		d     = make(map[int]int, len(nodes))
		delta = make(map[int]float64, len(nodes))
		queue internal.NodeQueue
	)
	for _, s := range nodes {
		stack = stack[:0]

		for _, w := range nodes {
			p[w.ID()] = p[w.ID()][:0]
		}

		for _, t := range nodes {
			sigma[t.ID()] = 0
			d[t.ID()] = -1
		}
		sigma[s.ID()] = 1
		d[s.ID()] = 0

		queue.Enqueue(s)
		for queue.Len() != 0 {
			v := queue.Dequeue()
			stack.Push(v)
			for _, w := range g.From(v) {
				// w found for the first time?
				if d[w.ID()] < 0 {
					queue.Enqueue(w)
					d[w.ID()] = d[v.ID()] + 1
				}
				// shortest path to w via v?
				if d[w.ID()] == d[v.ID()]+1 {
					sigma[w.ID()] += sigma[v.ID()]
					p[w.ID()] = append(p[w.ID()], v)
				}
			}
		}

		for _, v := range nodes {
			delta[v.ID()] = 0
		}
		// S returns vertices in order of non-increasing distance from s
		for stack.Len() != 0 {
			w := stack.Pop()
			for _, v := range p[w.ID()] {
				delta[v.ID()] += sigma[v.ID()] / sigma[w.ID()] * (1 + delta[w.ID()])
			}
			if w.ID() != s.ID() {
				if d := delta[w.ID()]; d != 0 {
					cb[w.ID()] += d
				}
			}
		}
	}

	return cb
}

// WeightedGraph is a graph with edge weights.
type WeightedGraph interface {
	graph.Graph
	graph.Weighter
}

// BetweennessWeighted returns the non-zero betweenness centrality for nodes in the weighted
// graph g used to construct the given shortest paths.
//
//  C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st})
//
// where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t,
// and the subset of those paths containing v respectively.
func BetweennessWeighted(g WeightedGraph, p path.AllShortest) map[int]float64 {
	cb := make(map[int]float64)

	nodes := g.Nodes()
	for i, s := range nodes {
		for j, t := range nodes {
			if i == j {
				continue
			}
			d := p.Weight(s, t)
			if math.IsInf(d, 0) {
				continue
			}

			sID := s.ID()
			tID := t.ID()

			// If we have a unique path, don't do the
			// extra work needed to get all paths.
			path, _, unique := p.Between(s, t)
			if unique {
				for _, v := range path {
					if vID := v.ID(); vID == sID || vID == tID {
						continue
					}
					// For undirected graphs we double count
					// passage though nodes. This is consistent
					// with Brandes' algorithm's behaviour.
					cb[v.ID()]++
				}
				continue
			}

			// Otherwise iterate over all paths.
			paths, _ := p.AllBetween(s, t)
			stFrac := 1 / float64(len(paths))
			for _, path := range paths {
				for _, v := range path {
					if vID := v.ID(); vID == sID || vID == tID {
						continue
					}
					cb[v.ID()] += stFrac
				}
			}
		}
	}

	return cb
}
<commit_msg>network: simplify logic of path end handling<commit_after>// Copyright ©2015 The gonum 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 network

import (
	"math"

	"github.com/gonum/graph"
	"github.com/gonum/graph/internal"
	"github.com/gonum/graph/path"
)

// Betweenness returns the non-zero betweenness centrality for nodes in the unweighted graph g.
//
//  C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st})
//
// where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t,
// and the subset of those paths containing v respectively.
func Betweenness(g graph.Graph) map[int]float64 {
	// Brandes' algorithm for finding betweenness centrality for nodes in
	// and unweighted graph:
	//
	// http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf

	// TODO(kortschak): Consider using the parallel algorithm when
	// GOMAXPROCS != 1.
	//
	// http://htor.inf.ethz.ch/publications/img/edmonds-hoefler-lumsdaine-bc.pdf

	// Also note special case for sparse networks:
	// http://wwwold.iit.cnr.it/staff/marco.pellegrini/papiri/asonam-final.pdf

	var (
		cb = make(map[int]float64)

		nodes = g.Nodes()
		stack internal.NodeStack
		p     = make(map[int][]graph.Node, len(nodes))
		sigma = make(map[int]float64, len(nodes))
		d     = make(map[int]int, len(nodes))
		delta = make(map[int]float64, len(nodes))
		queue internal.NodeQueue
	)
	for _, s := range nodes {
		stack = stack[:0]

		for _, w := range nodes {
			p[w.ID()] = p[w.ID()][:0]
		}

		for _, t := range nodes {
			sigma[t.ID()] = 0
			d[t.ID()] = -1
		}
		sigma[s.ID()] = 1
		d[s.ID()] = 0

		queue.Enqueue(s)
		for queue.Len() != 0 {
			v := queue.Dequeue()
			stack.Push(v)
			for _, w := range g.From(v) {
				// w found for the first time?
				if d[w.ID()] < 0 {
					queue.Enqueue(w)
					d[w.ID()] = d[v.ID()] + 1
				}
				// shortest path to w via v?
				if d[w.ID()] == d[v.ID()]+1 {
					sigma[w.ID()] += sigma[v.ID()]
					p[w.ID()] = append(p[w.ID()], v)
				}
			}
		}

		for _, v := range nodes {
			delta[v.ID()] = 0
		}
		// S returns vertices in order of non-increasing distance from s
		for stack.Len() != 0 {
			w := stack.Pop()
			for _, v := range p[w.ID()] {
				delta[v.ID()] += sigma[v.ID()] / sigma[w.ID()] * (1 + delta[w.ID()])
			}
			if w.ID() != s.ID() {
				if d := delta[w.ID()]; d != 0 {
					cb[w.ID()] += d
				}
			}
		}
	}

	return cb
}

// WeightedGraph is a graph with edge weights.
type WeightedGraph interface {
	graph.Graph
	graph.Weighter
}

// BetweennessWeighted returns the non-zero betweenness centrality for nodes in the weighted
// graph g used to construct the given shortest paths.
//
//  C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st})
//
// where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t,
// and the subset of those paths containing v respectively.
func BetweennessWeighted(g WeightedGraph, p path.AllShortest) map[int]float64 {
	cb := make(map[int]float64)

	nodes := g.Nodes()
	for i, s := range nodes {
		for j, t := range nodes {
			if i == j {
				continue
			}
			d := p.Weight(s, t)
			if math.IsInf(d, 0) {
				continue
			}

			// If we have a unique path, don't do the
			// extra work needed to get all paths.
			path, _, unique := p.Between(s, t)
			if unique {
				for _, v := range path[1 : len(path)-1] {
					// For undirected graphs we double count
					// passage though nodes. This is consistent
					// with Brandes' algorithm's behaviour.
					cb[v.ID()]++
				}
				continue
			}

			// Otherwise iterate over all paths.
			paths, _ := p.AllBetween(s, t)
			stFrac := 1 / float64(len(paths))
			for _, path := range paths {
				for _, v := range path[1 : len(path)-1] {
					cb[v.ID()] += stFrac
				}
			}
		}
	}

	return cb
}
<|endoftext|>