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

// Package exec runs external commands. It wraps os.StartProcess to make it
// easier to remap stdin and stdout, connect I/O with pipes, and do other
// adjustments.
package exec

import (
	"bytes"
	"errors"
	"io"
	"os"
	"strconv"
	"syscall"
)

// Error records the name of a binary that failed to be be executed
// and the reason it failed.
type Error struct {
	Name string
	Err  error
}

func (e *Error) Error() string {
	return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
}

// Cmd represents an external command being prepared or run.
type Cmd struct {
	// Path is the path of the command to run.
	//
	// This is the only field that must be set to a non-zero
	// value.
	Path string

	// Args holds command line arguments, including the command as Args[0].
	// If the Args field is empty or nil, Run uses {Path}.
	//
	// In typical use, both Path and Args are set by calling Command.
	Args []string

	// Env specifies the environment of the process.
	// If Env is nil, Run uses the current process's environment.
	Env []string

	// Dir specifies the working directory of the command.
	// If Dir is the empty string, Run runs the command in the
	// calling process's current directory.
	Dir string

	// Stdin specifies the process's standard input.
	// If Stdin is nil, the process reads from DevNull.
	Stdin io.Reader

	// Stdout and Stderr specify the process's standard output and error.
	//
	// If either is nil, Run connects the
	// corresponding file descriptor to /dev/null.
	//
	// If Stdout and Stderr are are the same writer, at most one
	// goroutine at a time will call Write.
	Stdout io.Writer
	Stderr io.Writer

	// ExtraFiles specifies additional open files to be inherited by the
	// new process. It does not include standard input, standard output, or
	// standard error. If non-nil, entry i becomes file descriptor 3+i.
	ExtraFiles []*os.File

	// SysProcAttr holds optional, operating system-specific attributes.
	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
	SysProcAttr *syscall.SysProcAttr

	// Process is the underlying process, once started.
	Process *os.Process

	err             error // last error (from LookPath, stdin, stdout, stderr)
	finished        bool  // when Wait was called
	childFiles      []*os.File
	closeAfterStart []io.Closer
	closeAfterWait  []io.Closer
	goroutine       []func() error
	errch           chan error // one send per goroutine
}

// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
// It sets Path and Args in the returned structure and zeroes the
// other fields.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
// name directly.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
	aname, err := LookPath(name)
	if err != nil {
		aname = name
	}
	return &Cmd{
		Path: aname,
		Args: append([]string{name}, arg...),
		err:  err,
	}
}

// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types
func interfaceEqual(a, b interface{}) bool {
	defer func() {
		recover()
	}()
	return a == b
}

func (c *Cmd) envv() []string {
	if c.Env != nil {
		return c.Env
	}
	return os.Environ()
}

func (c *Cmd) argv() []string {
	if len(c.Args) > 0 {
		return c.Args
	}
	return []string{c.Path}
}

func (c *Cmd) stdin() (f *os.File, err error) {
	if c.Stdin == nil {
		f, err = os.Open(os.DevNull)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := c.Stdin.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	c.goroutine = append(c.goroutine, func() error {
		_, err := io.Copy(pw, c.Stdin)
		if err1 := pw.Close(); err == nil {
			err = err1
		}
		return err
	})
	return pr, nil
}

func (c *Cmd) stdout() (f *os.File, err error) {
	return c.writerDescriptor(c.Stdout)
}

func (c *Cmd) stderr() (f *os.File, err error) {
	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
		return c.childFiles[1], nil
	}
	return c.writerDescriptor(c.Stderr)
}

func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
	if w == nil {
		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := w.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	c.goroutine = append(c.goroutine, func() error {
		_, err := io.Copy(w, pr)
		return err
	})
	return pw, nil
}

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
func (c *Cmd) Run() error {
	if err := c.Start(); err != nil {
		return err
	}
	return c.Wait()
}

// Start starts the specified command but does not wait for it to complete.
func (c *Cmd) Start() error {
	if c.err != nil {
		return c.err
	}
	if c.Process != nil {
		return errors.New("exec: already started")
	}

	type F func(*Cmd) (*os.File, error)
	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
		fd, err := setupFd(c)
		if err != nil {
			return err
		}
		c.childFiles = append(c.childFiles, fd)
	}
	c.childFiles = append(c.childFiles, c.ExtraFiles...)

	var err error
	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
		Dir:   c.Dir,
		Files: c.childFiles,
		Env:   c.envv(),
		Sys:   c.SysProcAttr,
	})
	if err != nil {
		return err
	}

	for _, fd := range c.closeAfterStart {
		fd.Close()
	}

	c.errch = make(chan error, len(c.goroutine))
	for _, fn := range c.goroutine {
		go func(fn func() error) {
			c.errch <- fn()
		}(fn)
	}

	return nil
}

// An ExitError reports an unsuccessful exit by a command.
type ExitError struct {
	*os.Waitmsg
}

func (e *ExitError) Error() string {
	return e.Waitmsg.String()
}

// Wait waits for the command to exit.
// It must have been started by Start.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
func (c *Cmd) Wait() error {
	if c.Process == nil {
		return errors.New("exec: not started")
	}
	if c.finished {
		return errors.New("exec: Wait was already called")
	}
	c.finished = true
	msg, err := c.Process.Wait(0)

	var copyError error
	for _ = range c.goroutine {
		if err := <-c.errch; err != nil && copyError == nil {
			copyError = err
		}
	}

	for _, fd := range c.closeAfterWait {
		fd.Close()
	}

	if err != nil {
		return err
	} else if !msg.Exited() || msg.ExitStatus() != 0 {
		return &ExitError{msg}
	}

	return copyError
}

// Output runs the command and returns its standard output.
func (c *Cmd) Output() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// CombinedOutput runs the command and returns its combined standard
// output and standard error.
func (c *Cmd) CombinedOutput() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// StdinPipe returns a pipe that will be connected to the command's
// standard input when the command starts.
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
	if c.Stdin != nil {
		return nil, errors.New("exec: Stdin already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StdinPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = pr
	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	return pw, nil
}

// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
// The pipe will be closed automatically after Wait sees the command exit.
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StdoutPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}

// StderrPipe returns a pipe that will be connected to the command's
// standard error when the command starts.
// The pipe will be closed automatically after Wait sees the command exit.
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
	if c.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StderrPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}
<commit_msg>os/exec: Fix documentation references to os.DevNull<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package exec runs external commands. It wraps os.StartProcess to make it
// easier to remap stdin and stdout, connect I/O with pipes, and do other
// adjustments.
package exec

import (
	"bytes"
	"errors"
	"io"
	"os"
	"strconv"
	"syscall"
)

// Error records the name of a binary that failed to be be executed
// and the reason it failed.
type Error struct {
	Name string
	Err  error
}

func (e *Error) Error() string {
	return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
}

// Cmd represents an external command being prepared or run.
type Cmd struct {
	// Path is the path of the command to run.
	//
	// This is the only field that must be set to a non-zero
	// value.
	Path string

	// Args holds command line arguments, including the command as Args[0].
	// If the Args field is empty or nil, Run uses {Path}.
	//
	// In typical use, both Path and Args are set by calling Command.
	Args []string

	// Env specifies the environment of the process.
	// If Env is nil, Run uses the current process's environment.
	Env []string

	// Dir specifies the working directory of the command.
	// If Dir is the empty string, Run runs the command in the
	// calling process's current directory.
	Dir string

	// Stdin specifies the process's standard input. If Stdin is
	// nil, the process reads from the null device (os.DevNull).
	Stdin io.Reader

	// Stdout and Stderr specify the process's standard output and error.
	//
	// If either is nil, Run connects the corresponding file descriptor
	// to the null device (os.DevNull).
	//
	// If Stdout and Stderr are are the same writer, at most one
	// goroutine at a time will call Write.
	Stdout io.Writer
	Stderr io.Writer

	// ExtraFiles specifies additional open files to be inherited by the
	// new process. It does not include standard input, standard output, or
	// standard error. If non-nil, entry i becomes file descriptor 3+i.
	ExtraFiles []*os.File

	// SysProcAttr holds optional, operating system-specific attributes.
	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
	SysProcAttr *syscall.SysProcAttr

	// Process is the underlying process, once started.
	Process *os.Process

	err             error // last error (from LookPath, stdin, stdout, stderr)
	finished        bool  // when Wait was called
	childFiles      []*os.File
	closeAfterStart []io.Closer
	closeAfterWait  []io.Closer
	goroutine       []func() error
	errch           chan error // one send per goroutine
}

// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
// It sets Path and Args in the returned structure and zeroes the
// other fields.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
// name directly.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
	aname, err := LookPath(name)
	if err != nil {
		aname = name
	}
	return &Cmd{
		Path: aname,
		Args: append([]string{name}, arg...),
		err:  err,
	}
}

// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types
func interfaceEqual(a, b interface{}) bool {
	defer func() {
		recover()
	}()
	return a == b
}

func (c *Cmd) envv() []string {
	if c.Env != nil {
		return c.Env
	}
	return os.Environ()
}

func (c *Cmd) argv() []string {
	if len(c.Args) > 0 {
		return c.Args
	}
	return []string{c.Path}
}

func (c *Cmd) stdin() (f *os.File, err error) {
	if c.Stdin == nil {
		f, err = os.Open(os.DevNull)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := c.Stdin.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	c.goroutine = append(c.goroutine, func() error {
		_, err := io.Copy(pw, c.Stdin)
		if err1 := pw.Close(); err == nil {
			err = err1
		}
		return err
	})
	return pr, nil
}

func (c *Cmd) stdout() (f *os.File, err error) {
	return c.writerDescriptor(c.Stdout)
}

func (c *Cmd) stderr() (f *os.File, err error) {
	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
		return c.childFiles[1], nil
	}
	return c.writerDescriptor(c.Stderr)
}

func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
	if w == nil {
		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := w.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	c.goroutine = append(c.goroutine, func() error {
		_, err := io.Copy(w, pr)
		return err
	})
	return pw, nil
}

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
func (c *Cmd) Run() error {
	if err := c.Start(); err != nil {
		return err
	}
	return c.Wait()
}

// Start starts the specified command but does not wait for it to complete.
func (c *Cmd) Start() error {
	if c.err != nil {
		return c.err
	}
	if c.Process != nil {
		return errors.New("exec: already started")
	}

	type F func(*Cmd) (*os.File, error)
	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
		fd, err := setupFd(c)
		if err != nil {
			return err
		}
		c.childFiles = append(c.childFiles, fd)
	}
	c.childFiles = append(c.childFiles, c.ExtraFiles...)

	var err error
	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
		Dir:   c.Dir,
		Files: c.childFiles,
		Env:   c.envv(),
		Sys:   c.SysProcAttr,
	})
	if err != nil {
		return err
	}

	for _, fd := range c.closeAfterStart {
		fd.Close()
	}

	c.errch = make(chan error, len(c.goroutine))
	for _, fn := range c.goroutine {
		go func(fn func() error) {
			c.errch <- fn()
		}(fn)
	}

	return nil
}

// An ExitError reports an unsuccessful exit by a command.
type ExitError struct {
	*os.Waitmsg
}

func (e *ExitError) Error() string {
	return e.Waitmsg.String()
}

// Wait waits for the command to exit.
// It must have been started by Start.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
func (c *Cmd) Wait() error {
	if c.Process == nil {
		return errors.New("exec: not started")
	}
	if c.finished {
		return errors.New("exec: Wait was already called")
	}
	c.finished = true
	msg, err := c.Process.Wait(0)

	var copyError error
	for _ = range c.goroutine {
		if err := <-c.errch; err != nil && copyError == nil {
			copyError = err
		}
	}

	for _, fd := range c.closeAfterWait {
		fd.Close()
	}

	if err != nil {
		return err
	} else if !msg.Exited() || msg.ExitStatus() != 0 {
		return &ExitError{msg}
	}

	return copyError
}

// Output runs the command and returns its standard output.
func (c *Cmd) Output() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// CombinedOutput runs the command and returns its combined standard
// output and standard error.
func (c *Cmd) CombinedOutput() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// StdinPipe returns a pipe that will be connected to the command's
// standard input when the command starts.
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
	if c.Stdin != nil {
		return nil, errors.New("exec: Stdin already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StdinPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = pr
	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	return pw, nil
}

// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
// The pipe will be closed automatically after Wait sees the command exit.
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StdoutPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}

// StderrPipe returns a pipe that will be connected to the command's
// standard error when the command starts.
// The pipe will be closed automatically after Wait sees the command exit.
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
	if c.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	if c.Process != nil {
		return nil, errors.New("exec: StderrPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}
<|endoftext|>


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

/*
 * Runtime type representation.
 *
 * The following files know the exact layout of these
 * data structures and must be kept in sync with this file:
 *
 *	../../cmd/gc/reflect.c
 *	../reflect/type.go
 *	type.h
 */

package runtime

import "unsafe"

// The compiler can only construct empty interface values at
// compile time; non-empty interface values get created
// during initialization.  Type is an empty interface
// so that the compiler can lay out references as data.
type Type interface{}

// All types begin with a few common fields needed for
// the interface runtime.
type commonType struct {
	size          uintptr // size in bytes
	hash          uint32  // hash of type; avoids computation in hash tables
	alg           uint8   // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM)
	align         uint8   // alignment of variable with this type
	fieldAlign    uint8   // alignment of struct field with this type
	kind          uint8   // enumeration for C
	string        *string // string form; unnecessary  but undeniably useful
	*uncommonType         // (relatively) uncommon fields
}

// Values for commonType.kind.
const (
	kindBool = 1 + iota
	kindInt
	kindInt8
	kindInt16
	kindInt32
	kindInt64
	kindUint
	kindUint8
	kindUint16
	kindUint32
	kindUint64
	kindUintptr
	kindFloat
	kindFloat32
	kindFloat64
	kindArray
	kindChan
	kindFunc
	kindInterface
	kindMap
	kindPtr
	kindSlice
	kindString
	kindStruct
	kindUnsafePointer

	kindNoPointers = 1 << 7 // OR'ed into kind
)

// Method on non-interface type
type method struct {
	name    *string        // name of method
	pkgPath *string        // nil for exported Names; otherwise import path
	mtyp    *Type          // method type (without receiver)
	typ     *Type          // .(*FuncType) underneath (with receiver)
	ifn     unsafe.Pointer // fn used in interface call (one-word receiver)
	tfn     unsafe.Pointer // fn used for normal method call
}

// uncommonType is present only for types with names or methods
// (if T is a named type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
	name    *string  // name of type
	pkgPath *string  // import path; nil for built-in types like int, string
	methods []method // methods associated with type
}

// BoolType represents a boolean type.
type BoolType commonType

// FloatType represents a float type.
type FloatType commonType

// ComplexType represents a complex type.
type ComplexType commonType

// IntType represents an int type.
type IntType commonType

// UintType represents a uint type.
type UintType commonType

// StringType represents a string type.
type StringType commonType

// UintptrType represents a uintptr type.
type UintptrType commonType

// UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType commonType

// ArrayType represents a fixed array type.
type ArrayType struct {
	commonType
	elem *Type // array element type
	len  uintptr
}

// SliceType represents a slice type.
type SliceType struct {
	commonType
	elem *Type // slice element type
}

// ChanDir represents a channel type's direction.
type ChanDir int

const (
	RecvDir ChanDir             = 1 << iota // <-chan
	SendDir                                 // chan<-
	BothDir = RecvDir | SendDir             // chan
)

// ChanType represents a channel type.
type ChanType struct {
	commonType
	elem *Type   // channel element type
	dir  uintptr // channel direction (ChanDir)
}

// FuncType represents a function type.
type FuncType struct {
	commonType
	dotdotdot bool    // last input parameter is ...
	in        []*Type // input parameter types
	out       []*Type // output parameter types
}

// Method on interface type
type imethod struct {
	name    *string // name of method
	pkgPath *string // nil for exported Names; otherwise import path
	typ     *Type   // .(*FuncType) underneath
}

// InterfaceType represents an interface type.
type InterfaceType struct {
	commonType
	methods []imethod // sorted by hash
}

// MapType represents a map type.
type MapType struct {
	commonType
	key  *Type // map key type
	elem *Type // map element (value) type
}

// PtrType represents a pointer type.
type PtrType struct {
	commonType
	elem *Type // pointer element (pointed at) type
}

// Struct field
type structField struct {
	name    *string // nil for embedded fields
	pkgPath *string // nil for exported Names; otherwise import path
	typ     *Type   // type of field
	tag     *string // nil if no tag
	offset  uintptr // byte offset of field within struct
}

// StructType represents a struct type.
type StructType struct {
	commonType
	fields []structField // sorted by offset
}

/*
 * Must match iface.c:/Itab and compilers.
 */
type Itable struct {
	Itype  *Type // (*tab.inter).(*InterfaceType) is the interface type
	Type   *Type
	link   *Itable
	bad    int32
	unused int32
	Fn     [100000]uintptr // bigger than we'll ever see
}
<commit_msg>runtime: Correct commonType.kind values to match compiler.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
 * Runtime type representation.
 *
 * The following files know the exact layout of these
 * data structures and must be kept in sync with this file:
 *
 *	../../cmd/gc/reflect.c
 *	../reflect/type.go
 *	type.h
 */

package runtime

import "unsafe"

// The compiler can only construct empty interface values at
// compile time; non-empty interface values get created
// during initialization.  Type is an empty interface
// so that the compiler can lay out references as data.
type Type interface{}

// All types begin with a few common fields needed for
// the interface runtime.
type commonType struct {
	size          uintptr // size in bytes
	hash          uint32  // hash of type; avoids computation in hash tables
	alg           uint8   // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM)
	align         uint8   // alignment of variable with this type
	fieldAlign    uint8   // alignment of struct field with this type
	kind          uint8   // enumeration for C
	string        *string // string form; unnecessary  but undeniably useful
	*uncommonType         // (relatively) uncommon fields
}

// Values for commonType.kind.
const (
	kindBool = 1 + iota
	kindInt
	kindInt8
	kindInt16
	kindInt32
	kindInt64
	kindUint
	kindUint8
	kindUint16
	kindUint32
	kindUint64
	kindUintptr
	kindFloat
	kindFloat32
	kindFloat64
	kindComplex
	kindComplex64
	kindComplex128
	kindArray
	kindChan
	kindFunc
	kindInterface
	kindMap
	kindPtr
	kindSlice
	kindString
	kindStruct
	kindUnsafePointer

	kindNoPointers = 1 << 7 // OR'ed into kind
)

// Method on non-interface type
type method struct {
	name    *string        // name of method
	pkgPath *string        // nil for exported Names; otherwise import path
	mtyp    *Type          // method type (without receiver)
	typ     *Type          // .(*FuncType) underneath (with receiver)
	ifn     unsafe.Pointer // fn used in interface call (one-word receiver)
	tfn     unsafe.Pointer // fn used for normal method call
}

// uncommonType is present only for types with names or methods
// (if T is a named type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
	name    *string  // name of type
	pkgPath *string  // import path; nil for built-in types like int, string
	methods []method // methods associated with type
}

// BoolType represents a boolean type.
type BoolType commonType

// FloatType represents a float type.
type FloatType commonType

// ComplexType represents a complex type.
type ComplexType commonType

// IntType represents an int type.
type IntType commonType

// UintType represents a uint type.
type UintType commonType

// StringType represents a string type.
type StringType commonType

// UintptrType represents a uintptr type.
type UintptrType commonType

// UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType commonType

// ArrayType represents a fixed array type.
type ArrayType struct {
	commonType
	elem *Type // array element type
	len  uintptr
}

// SliceType represents a slice type.
type SliceType struct {
	commonType
	elem *Type // slice element type
}

// ChanDir represents a channel type's direction.
type ChanDir int

const (
	RecvDir ChanDir             = 1 << iota // <-chan
	SendDir                                 // chan<-
	BothDir = RecvDir | SendDir             // chan
)

// ChanType represents a channel type.
type ChanType struct {
	commonType
	elem *Type   // channel element type
	dir  uintptr // channel direction (ChanDir)
}

// FuncType represents a function type.
type FuncType struct {
	commonType
	dotdotdot bool    // last input parameter is ...
	in        []*Type // input parameter types
	out       []*Type // output parameter types
}

// Method on interface type
type imethod struct {
	name    *string // name of method
	pkgPath *string // nil for exported Names; otherwise import path
	typ     *Type   // .(*FuncType) underneath
}

// InterfaceType represents an interface type.
type InterfaceType struct {
	commonType
	methods []imethod // sorted by hash
}

// MapType represents a map type.
type MapType struct {
	commonType
	key  *Type // map key type
	elem *Type // map element (value) type
}

// PtrType represents a pointer type.
type PtrType struct {
	commonType
	elem *Type // pointer element (pointed at) type
}

// Struct field
type structField struct {
	name    *string // nil for embedded fields
	pkgPath *string // nil for exported Names; otherwise import path
	typ     *Type   // type of field
	tag     *string // nil if no tag
	offset  uintptr // byte offset of field within struct
}

// StructType represents a struct type.
type StructType struct {
	commonType
	fields []structField // sorted by offset
}

/*
 * Must match iface.c:/Itab and compilers.
 */
type Itable struct {
	Itype  *Type // (*tab.inter).(*InterfaceType) is the interface type
	Type   *Type
	link   *Itable
	bad    int32
	unused int32
	Fn     [100000]uintptr // bigger than we'll ever see
}
<|endoftext|>


<commit_before>package qshell

import (
	"bufio"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/qiniu/api/auth/digest"
	fio "github.com/qiniu/api/io"
	rio "github.com/qiniu/api/resumable/io"
	"github.com/qiniu/api/rs"
	"github.com/qiniu/log"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"io/ioutil"
	"os"
	"os/user"
	"strings"
)

/*
Config file like:

{
	"src_dir" 		:	"/Users/jemy/Photos",
	"access_key" 	:	"<Your AccessKey>",
	"secret_key"	:	"<Your SecretKey>",
	"bucket"		:	"test-bucket",
	"ignore_dir"	:	false,
	"key_prefix"	:	"2014/12/01/"
}

or without key_prefix and ignore_dir

{
	"src_dir" 		:	"/Users/jemy/Photos",
	"access_key" 	:	"<Your AccessKey>",
	"secret_key"	:	"<Your SecretKey>",
	"bucket"		:	"test-bucket",
}
*/

const (
	PUT_THRESHOLD int64 = 2 << 30
)

type UploadConfig struct {
	SrcDir    string `json:"src_dir"`
	AccessKey string `json:"access_key"`
	SecretKey string `json:"secret_key"`
	Bucket    string `json:"bucket"`
	KeyPrefix string `json:"key_prefix,omitempty"`
	IgnoreDir bool   `json:"ignore_dir,omitempty"`
}

func QiniuUpload(putThreshold int64, uploadConfigFile string) {
	fp, err := os.Open(uploadConfigFile)
	if err != nil {
		log.Error(fmt.Sprintf("Open upload config file `%s' error due to `%s'", uploadConfigFile, err))
		return
	}
	defer fp.Close()
	configData, err := ioutil.ReadAll(fp)
	if err != nil {
		log.Error(fmt.Sprintf("Read upload config file `%s' error due to `%s'", uploadConfigFile, err))
		return
	}
	var uploadConfig UploadConfig
	err = json.Unmarshal(configData, &uploadConfig)
	if err != nil {
		log.Error(fmt.Sprintf("Parse upload config file `%s' errror due to `%s'", uploadConfigFile, err))
		return
	}
	if _, err := os.Stat(uploadConfig.SrcDir); err != nil {
		log.Error("Upload config error for parameter `SrcDir`,", err)
		return
	}
	dirCache := DirCache{}
	currentUser, err := user.Current()
	if err != nil {
		log.Error("Failed to get current user", err)
		return
	}
	config, _ := json.Marshal(&uploadConfig)
	md5Sum := md5.Sum(config)
	storePath := fmt.Sprintf("%s/.qshell/qupload", currentUser.HomeDir)
	err = os.MkdirAll(storePath, 0775)
	if err != nil {
		log.Error(fmt.Sprintf("Failed to mkdir `%s' due to `%s'", storePath, err))
		return
	}
	cacheFileName := fmt.Sprintf("%s/%x.cache", storePath, md5Sum)
	leveldbFileName := fmt.Sprintf("%s/%x.ldb", storePath, md5Sum)
	listFileName := fmt.Sprintf("%s/%x.list", storePath, md5Sum)
	totalFileCount := dirCache.Cache(uploadConfig.SrcDir, cacheFileName)
	ldb, err := leveldb.OpenFile(leveldbFileName, nil)
	if err != nil {
		log.Error(fmt.Sprintf("Open leveldb `%s' failed due to `%s'", leveldbFileName, err))
		return
	}
	defer ldb.Close()
	//sync
	ufp, err := os.Open(cacheFileName)
	if err != nil {
		log.Error(fmt.Sprintf("Open cache file `%s' failed due to `%s'", cacheFileName, err))
		return
	}
	defer ufp.Close()
	bScanner := bufio.NewScanner(ufp)
	bScanner.Split(bufio.ScanLines)
	currentFileCount := 0
	ldbWOpt := opt.WriteOptions{
		Sync: true,
	}

	for bScanner.Scan() {
		line := strings.TrimSpace(bScanner.Text())
		items := strings.Split(line, "\t")
		if len(items) > 1 {
			localFname := items[0]
			uploadFname := localFname
			if uploadConfig.IgnoreDir {
				if i := strings.LastIndex(uploadFname, string(os.PathSeparator)); i != -1 {
					uploadFname = uploadFname[i+1:]
				}
			}
			if uploadConfig.KeyPrefix != "" {
				uploadFname = strings.Join([]string{uploadConfig.KeyPrefix, uploadFname}, "")
			}
			localFnameFull := strings.Join([]string{uploadConfig.SrcDir, localFname}, string(os.PathSeparator))
			//check leveldb
			currentFileCount += 1
			ldbKey := fmt.Sprintf("%s => %s", localFnameFull, uploadFname)
			log.Debug(fmt.Sprintf("Checking %s ...", ldbKey))
			_, err := ldb.Get([]byte(ldbKey), nil)
			//not exist, return ErrNotFound
			if err == nil {
				continue
			}
			fmt.Print("\033[2K\r")
			fmt.Printf("Uploading %s (%d/%d, %.0f%%) ...", ldbKey, currentFileCount, totalFileCount,
				float32(currentFileCount)*100/float32(totalFileCount))
			os.Stdout.Sync()
			fstat, err := os.Stat(localFnameFull)
			if err != nil {
				log.Error(fmt.Sprintf("Error stat local file `%s' due to `%s'", localFnameFull, err))
				continue
			}
			fsize := fstat.Size()
			mac := digest.Mac{uploadConfig.AccessKey, []byte(uploadConfig.SecretKey)}
			policy := rs.PutPolicy{}
			policy.Scope = uploadConfig.Bucket
			policy.Expires = 24 * 3600
			uptoken := policy.Token(&mac)
			if fsize > putThreshold {
				putRet := rio.PutRet{}
				err := rio.PutFile(nil, &putRet, uptoken, uploadFname, localFnameFull, nil)
				if err != nil {
					log.Error(fmt.Sprintf("Put file `%s' => `%s' failed due to `%s'", localFnameFull, uploadFname, err))
				} else {
					perr := ldb.Put([]byte(ldbKey), []byte("Y"), &ldbWOpt)
					if perr != nil {
						log.Error(fmt.Sprintf("Put key `%s' into leveldb error due to `%s'", ldbKey, perr))
					}
				}
			} else {
				putRet := fio.PutRet{}
				err := fio.PutFile(nil, &putRet, uptoken, uploadFname, localFnameFull, nil)
				if err != nil {
					log.Error(fmt.Sprintf("Put file `%s' => `%s' failed due to `%s'", localFnameFull, uploadFname, err))
				} else {
					perr := ldb.Put([]byte(ldbKey), []byte("Y"), &ldbWOpt)
					if perr != nil {
						log.Error(fmt.Sprintf("Put key `%s' into leveldb error due to `%s'", ldbKey, perr))
					}
				}
			}
		} else {
			log.Error(fmt.Sprintf("Error cache line `%s'", line))
		}
	}
	fmt.Println()
	fmt.Println("Upload done!")
	//list bucket
	acct := Account{
		uploadConfig.AccessKey,
		uploadConfig.SecretKey,
	}
	bucketLister := ListBucket{
		Account: acct,
	}
	fmt.Println("Listing bucket...")
	bucketLister.List(uploadConfig.Bucket, uploadConfig.KeyPrefix, listFileName)
	//check data integrity
	fmt.Println("Checking data integrity...")
	CheckQrsync(cacheFileName, listFileName, uploadConfig.IgnoreDir, uploadConfig.KeyPrefix)
}
<commit_msg>Make each qupload log in a separate folder under ~/.qshell/qupload<commit_after>package qshell

import (
	"bufio"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/qiniu/api/auth/digest"
	fio "github.com/qiniu/api/io"
	rio "github.com/qiniu/api/resumable/io"
	"github.com/qiniu/api/rs"
	"github.com/qiniu/log"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"io/ioutil"
	"os"
	"os/user"
	"strings"
)

/*
Config file like:

{
	"src_dir" 		:	"/Users/jemy/Photos",
	"access_key" 	:	"<Your AccessKey>",
	"secret_key"	:	"<Your SecretKey>",
	"bucket"		:	"test-bucket",
	"ignore_dir"	:	false,
	"key_prefix"	:	"2014/12/01/"
}

or without key_prefix and ignore_dir

{
	"src_dir" 		:	"/Users/jemy/Photos",
	"access_key" 	:	"<Your AccessKey>",
	"secret_key"	:	"<Your SecretKey>",
	"bucket"		:	"test-bucket",
}
*/

const (
	PUT_THRESHOLD int64 = 2 << 30
)

type UploadConfig struct {
	SrcDir    string `json:"src_dir"`
	AccessKey string `json:"access_key"`
	SecretKey string `json:"secret_key"`
	Bucket    string `json:"bucket"`
	KeyPrefix string `json:"key_prefix,omitempty"`
	IgnoreDir bool   `json:"ignore_dir,omitempty"`
}

func QiniuUpload(putThreshold int64, uploadConfigFile string) {
	fp, err := os.Open(uploadConfigFile)
	if err != nil {
		log.Error(fmt.Sprintf("Open upload config file `%s' error due to `%s'", uploadConfigFile, err))
		return
	}
	defer fp.Close()
	configData, err := ioutil.ReadAll(fp)
	if err != nil {
		log.Error(fmt.Sprintf("Read upload config file `%s' error due to `%s'", uploadConfigFile, err))
		return
	}
	var uploadConfig UploadConfig
	err = json.Unmarshal(configData, &uploadConfig)
	if err != nil {
		log.Error(fmt.Sprintf("Parse upload config file `%s' errror due to `%s'", uploadConfigFile, err))
		return
	}
	if _, err := os.Stat(uploadConfig.SrcDir); err != nil {
		log.Error("Upload config error for parameter `SrcDir`,", err)
		return
	}
	dirCache := DirCache{}
	currentUser, err := user.Current()
	if err != nil {
		log.Error("Failed to get current user", err)
		return
	}
	config, _ := json.Marshal(&uploadConfig)
	md5Sum := md5.Sum(config)
	storePath := fmt.Sprintf("%s/.qshell/qupload/%x", currentUser.HomeDir, md5Sum)
	err = os.MkdirAll(storePath, 0775)
	if err != nil {
		log.Error(fmt.Sprintf("Failed to mkdir `%s' due to `%s'", storePath, err))
		return
	}
	cacheFileName := fmt.Sprintf("%s/%x.cache", storePath, md5Sum)
	leveldbFileName := fmt.Sprintf("%s/%x.ldb", storePath, md5Sum)
	listFileName := fmt.Sprintf("%s/%x.list", storePath, md5Sum)
	totalFileCount := dirCache.Cache(uploadConfig.SrcDir, cacheFileName)
	ldb, err := leveldb.OpenFile(leveldbFileName, nil)
	if err != nil {
		log.Error(fmt.Sprintf("Open leveldb `%s' failed due to `%s'", leveldbFileName, err))
		return
	}
	defer ldb.Close()
	//sync
	ufp, err := os.Open(cacheFileName)
	if err != nil {
		log.Error(fmt.Sprintf("Open cache file `%s' failed due to `%s'", cacheFileName, err))
		return
	}
	defer ufp.Close()
	bScanner := bufio.NewScanner(ufp)
	bScanner.Split(bufio.ScanLines)
	currentFileCount := 0
	ldbWOpt := opt.WriteOptions{
		Sync: true,
	}

	for bScanner.Scan() {
		line := strings.TrimSpace(bScanner.Text())
		items := strings.Split(line, "\t")
		if len(items) > 1 {
			localFname := items[0]
			uploadFname := localFname
			if uploadConfig.IgnoreDir {
				if i := strings.LastIndex(uploadFname, string(os.PathSeparator)); i != -1 {
					uploadFname = uploadFname[i+1:]
				}
			}
			if uploadConfig.KeyPrefix != "" {
				uploadFname = strings.Join([]string{uploadConfig.KeyPrefix, uploadFname}, "")
			}
			localFnameFull := strings.Join([]string{uploadConfig.SrcDir, localFname}, string(os.PathSeparator))
			//check leveldb
			currentFileCount += 1
			ldbKey := fmt.Sprintf("%s => %s", localFnameFull, uploadFname)
			log.Debug(fmt.Sprintf("Checking %s ...", ldbKey))
			_, err := ldb.Get([]byte(ldbKey), nil)
			//not exist, return ErrNotFound
			if err == nil {
				continue
			}
			fmt.Print("\033[2K\r")
			fmt.Printf("Uploading %s (%d/%d, %.0f%%) ...", ldbKey, currentFileCount, totalFileCount,
				float32(currentFileCount)*100/float32(totalFileCount))
			os.Stdout.Sync()
			fstat, err := os.Stat(localFnameFull)
			if err != nil {
				log.Error(fmt.Sprintf("Error stat local file `%s' due to `%s'", localFnameFull, err))
				continue
			}
			fsize := fstat.Size()
			mac := digest.Mac{uploadConfig.AccessKey, []byte(uploadConfig.SecretKey)}
			policy := rs.PutPolicy{}
			policy.Scope = uploadConfig.Bucket
			policy.Expires = 24 * 3600
			uptoken := policy.Token(&mac)
			if fsize > putThreshold {
				putRet := rio.PutRet{}
				err := rio.PutFile(nil, &putRet, uptoken, uploadFname, localFnameFull, nil)
				if err != nil {
					log.Error(fmt.Sprintf("Put file `%s' => `%s' failed due to `%s'", localFnameFull, uploadFname, err))
				} else {
					perr := ldb.Put([]byte(ldbKey), []byte("Y"), &ldbWOpt)
					if perr != nil {
						log.Error(fmt.Sprintf("Put key `%s' into leveldb error due to `%s'", ldbKey, perr))
					}
				}
			} else {
				putRet := fio.PutRet{}
				err := fio.PutFile(nil, &putRet, uptoken, uploadFname, localFnameFull, nil)
				if err != nil {
					log.Error(fmt.Sprintf("Put file `%s' => `%s' failed due to `%s'", localFnameFull, uploadFname, err))
				} else {
					perr := ldb.Put([]byte(ldbKey), []byte("Y"), &ldbWOpt)
					if perr != nil {
						log.Error(fmt.Sprintf("Put key `%s' into leveldb error due to `%s'", ldbKey, perr))
					}
				}
			}
		} else {
			log.Error(fmt.Sprintf("Error cache line `%s'", line))
		}
	}
	fmt.Println()
	fmt.Println("Upload done!")
	//list bucket
	acct := Account{
		uploadConfig.AccessKey,
		uploadConfig.SecretKey,
	}
	bucketLister := ListBucket{
		Account: acct,
	}
	fmt.Println("Listing bucket...")
	bucketLister.List(uploadConfig.Bucket, uploadConfig.KeyPrefix, listFileName)
	//check data integrity
	fmt.Println("Checking data integrity...")
	CheckQrsync(cacheFileName, listFileName, uploadConfig.IgnoreDir, uploadConfig.KeyPrefix)
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/cloudfoundry/libbuildpack"
)

type Metadata struct {
	Stack         string
	SecretKeyBase string
}

type Cache struct {
	buildDir string
	cacheDir string
	depDir   string
	names    []string
	metadata Metadata
	log      *libbuildpack.Logger
	yaml     YAML
}

type Stager interface {
	BuildDir() string
	CacheDir() string
	DepDir() string
}

type YAML interface {
	Load(file string, obj interface{}) error
	Write(dest string, obj interface{}) error
}

func New(stager Stager, log *libbuildpack.Logger, yaml YAML) (*Cache, error) {
	c := &Cache{
		buildDir: stager.BuildDir(),
		cacheDir: stager.CacheDir(),
		depDir:   filepath.Join(stager.DepDir()),
		names:    []string{"vendor_bundle", "node_modules"},
		metadata: Metadata{},
		log:      log,
		yaml:     yaml,
	}

	if err := yaml.Load(c.metadata_yml(), &c.metadata); err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
	}

	return c, nil
}

func (c *Cache) Metadata() *Metadata {
	return &c.metadata
}

func (c *Cache) Restore() error {
	if c.metadata.Stack == os.Getenv("CF_STACK") {
		for _, name := range c.names {
			if exists, err := libbuildpack.FileExists(filepath.Join(c.cacheDir, name)); err != nil {
				return err
			} else if exists {
				c.log.BeginStep("Restoring %s from cache", name)
				if err := os.Rename(filepath.Join(c.cacheDir, name), filepath.Join(c.depDir, name)); err != nil {
					return err
				}
			}
		}
	}
	if c.metadata.Stack != "" {
		c.log.BeginStep("Skipping restoring vendor_bundle from cache, stack changed from %s to %s", c.metadata.Stack, os.Getenv("CF_STACK"))
	}
	return os.RemoveAll(filepath.Join(c.cacheDir, "vendor_bundle"))
}

func (c *Cache) Save() error {
	for _, name := range c.names {
		if exists, err := libbuildpack.FileExists(filepath.Join(c.depDir, name)); err != nil {
			return err
		} else if exists {
			c.log.BeginStep("Saving %s to cache", name)
			cmd := exec.Command("cp", "-al", filepath.Join(c.depDir, name), filepath.Join(c.cacheDir, name))
			if output, err := cmd.CombinedOutput(); err != nil {
				c.log.Error(string(output))
				return fmt.Errorf("Could not copy %s: %v", name, err)
			}
		}
	}

	c.metadata.Stack = os.Getenv("CF_STACK")
	if err := c.yaml.Write(c.metadata_yml(), c.metadata); err != nil {
		return err
	}

	return nil
}

func (c *Cache) metadata_yml() string {
	return filepath.Join(c.cacheDir, "metadata.yml")
}
<commit_msg>Only check oldStack not empty if not the same as current<commit_after>package cache

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/cloudfoundry/libbuildpack"
)

type Metadata struct {
	Stack         string
	SecretKeyBase string
}

type Cache struct {
	buildDir string
	cacheDir string
	depDir   string
	names    []string
	metadata Metadata
	log      *libbuildpack.Logger
	yaml     YAML
}

type Stager interface {
	BuildDir() string
	CacheDir() string
	DepDir() string
}

type YAML interface {
	Load(file string, obj interface{}) error
	Write(dest string, obj interface{}) error
}

func New(stager Stager, log *libbuildpack.Logger, yaml YAML) (*Cache, error) {
	c := &Cache{
		buildDir: stager.BuildDir(),
		cacheDir: stager.CacheDir(),
		depDir:   filepath.Join(stager.DepDir()),
		names:    []string{"vendor_bundle", "node_modules"},
		metadata: Metadata{},
		log:      log,
		yaml:     yaml,
	}

	if err := yaml.Load(c.metadata_yml(), &c.metadata); err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
	}

	return c, nil
}

func (c *Cache) Metadata() *Metadata {
	return &c.metadata
}

func (c *Cache) Restore() error {
	if c.metadata.Stack == os.Getenv("CF_STACK") {
		for _, name := range c.names {
			if exists, err := libbuildpack.FileExists(filepath.Join(c.cacheDir, name)); err != nil {
				return err
			} else if exists {
				c.log.BeginStep("Restoring %s from cache", name)
				if err := os.Rename(filepath.Join(c.cacheDir, name), filepath.Join(c.depDir, name)); err != nil {
					return err
				}
			}
		}
	} else if c.metadata.Stack != "" {
		c.log.BeginStep("Skipping restoring vendor_bundle from cache, stack changed from %s to %s", c.metadata.Stack, os.Getenv("CF_STACK"))
	}
	return os.RemoveAll(filepath.Join(c.cacheDir, "vendor_bundle"))
}

func (c *Cache) Save() error {
	for _, name := range c.names {
		if exists, err := libbuildpack.FileExists(filepath.Join(c.depDir, name)); err != nil {
			return err
		} else if exists {
			c.log.BeginStep("Saving %s to cache", name)
			cmd := exec.Command("cp", "-al", filepath.Join(c.depDir, name), filepath.Join(c.cacheDir, name))
			if output, err := cmd.CombinedOutput(); err != nil {
				c.log.Error(string(output))
				return fmt.Errorf("Could not copy %s: %v", name, err)
			}
		}
	}

	c.metadata.Stack = os.Getenv("CF_STACK")
	if err := c.yaml.Write(c.metadata_yml(), c.metadata); err != nil {
		return err
	}

	return nil
}

func (c *Cache) metadata_yml() string {
	return filepath.Join(c.cacheDir, "metadata.yml")
}
<|endoftext|>


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

package runtime

import "unsafe"

type ptrAlignError struct {
	ptr  unsafe.Pointer
	elem *_type
	n    uintptr
}

func (e ptrAlignError) RuntimeError() {}

func (e ptrAlignError) Error() string {
	return "runtime error: unsafe pointer conversion"
}

func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
	// Check that (*[n]elem)(p) is appropriately aligned.
	// TODO(mdempsky): What about fieldAlign?
	if uintptr(p)&(uintptr(elem.align)-1) != 0 {
		panic(ptrAlignError{p, elem, n})
	}

	// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
	if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
		panic(ptrAlignError{p, elem, n})
	}
}

type ptrArithError struct {
	ptr       unsafe.Pointer
	originals []unsafe.Pointer
}

func (e ptrArithError) RuntimeError() {}

func (e ptrArithError) Error() string {
	return "runtime error: unsafe pointer arithmetic"
}

func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
	if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
		panic(ptrArithError{p, originals})
	}

	// Check that if the computed pointer p points into a heap
	// object, then one of the original pointers must have pointed
	// into the same object.
	base := checkptrBase(p)
	if base == 0 {
		return
	}

	for _, original := range originals {
		if base == checkptrBase(original) {
			return
		}
	}

	panic(ptrArithError{p, originals})
}

// checkptrBase returns the base address for the allocation containing
// the address p.
//
// Importantly, if p1 and p2 point into the same variable, then
// checkptrBase(p1) == checkptrBase(p2). However, the converse/inverse
// is not necessarily true as allocations can have trailing padding,
// and multiple variables may be packed into a single allocation.
func checkptrBase(p unsafe.Pointer) uintptr {
	// stack
	if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi {
		// TODO(mdempsky): Walk the stack to identify the
		// specific stack frame or even stack object that p
		// points into.
		//
		// In the mean time, use "1" as a pseudo-address to
		// represent the stack. This is an invalid address on
		// all platforms, so it's guaranteed to be distinct
		// from any of the addresses we might return below.
		return 1
	}

	// heap (must check after stack because of #35068)
	if base, _, _ := findObject(uintptr(p), 0, 0); base != 0 {
		return base
	}

	// data or bss
	for _, datap := range activeModules() {
		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
			return datap.data
		}
		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
			return datap.bss
		}
	}

	return 0
}
<commit_msg>runtime: change checkptr to use throw instead of panic<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
	// Check that (*[n]elem)(p) is appropriately aligned.
	// TODO(mdempsky): What about fieldAlign?
	if uintptr(p)&(uintptr(elem.align)-1) != 0 {
		throw("checkptr: unsafe pointer conversion")
	}

	// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
	if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
		throw("checkptr: unsafe pointer conversion")
	}
}

func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
	if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
		throw("checkptr: unsafe pointer arithmetic")
	}

	// Check that if the computed pointer p points into a heap
	// object, then one of the original pointers must have pointed
	// into the same object.
	base := checkptrBase(p)
	if base == 0 {
		return
	}

	for _, original := range originals {
		if base == checkptrBase(original) {
			return
		}
	}

	throw("checkptr: unsafe pointer arithmetic")
}

// checkptrBase returns the base address for the allocation containing
// the address p.
//
// Importantly, if p1 and p2 point into the same variable, then
// checkptrBase(p1) == checkptrBase(p2). However, the converse/inverse
// is not necessarily true as allocations can have trailing padding,
// and multiple variables may be packed into a single allocation.
func checkptrBase(p unsafe.Pointer) uintptr {
	// stack
	if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi {
		// TODO(mdempsky): Walk the stack to identify the
		// specific stack frame or even stack object that p
		// points into.
		//
		// In the mean time, use "1" as a pseudo-address to
		// represent the stack. This is an invalid address on
		// all platforms, so it's guaranteed to be distinct
		// from any of the addresses we might return below.
		return 1
	}

	// heap (must check after stack because of #35068)
	if base, _, _ := findObject(uintptr(p), 0, 0); base != 0 {
		return base
	}

	// data or bss
	for _, datap := range activeModules() {
		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
			return datap.data
		}
		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
			return datap.bss
		}
	}

	return 0
}
<|endoftext|>


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

// Garbage collector: write barriers.
//
// For the concurrent garbage collector, the Go compiler implements
// updates to pointer-valued fields that may be in heap objects by
// emitting calls to write barriers. This file contains the actual write barrier
// implementation, markwb, and the various wrappers called by the
// compiler to implement pointer assignment, slice assignment,
// typed memmove, and so on.

package runtime

import "unsafe"

// markwb is the mark-phase write barrier, the only barrier we have.
// The rest of this file exists only to make calls to this function.
//
// This is the Dijkstra barrier coarsened to always shade the ptr (dst) object.
// The original Dijkstra barrier only shaded ptrs being placed in black slots.
//
// Shade indicates that it has seen a white pointer by adding the referent
// to wbuf as well as marking it.
//
// slot is the destination (dst) in go code
// ptr is the value that goes into the slot (src) in the go code
//
//
// Dealing with memory ordering:
//
// Dijkstra pointed out that maintaining the no black to white
// pointers means that white to white pointers not need
// to be noted by the write barrier. Furthermore if either
// white object dies before it is reached by the
// GC then the object can be collected during this GC cycle
// instead of waiting for the next cycle. Unfortunately the cost of
// ensure that the object holding the slot doesn't concurrently
// change to black without the mutator noticing seems prohibitive.
//
// Consider the following example where the mutator writes into
// a slot and then loads the slot's mark bit while the GC thread
// writes to the slot's mark bit and then as part of scanning reads
// the slot.
//
// Initially both [slot] and [slotmark] are 0 (nil)
// Mutator thread          GC thread
// st [slot], ptr          st [slotmark], 1
//
// ld r1, [slotmark]       ld r2, [slot]
//
// Without an expensive memory barrier between the st and the ld, the final
// result on most HW (including 386/amd64) can be r1==r2==0. This is a classic
// example of what can happen when loads are allowed to be reordered with older
// stores (avoiding such reorderings lies at the heart of the classic
// Peterson/Dekker algorithms for mutual exclusion). Rather than require memory
// barriers, which will slow down both the mutator and the GC, we always grey
// the ptr object regardless of the slot's color.
//
// Another place where we intentionally omit memory barriers is when
// accessing mheap_.arena_used to check if a pointer points into the
// heap. On relaxed memory machines, it's possible for a mutator to
// extend the size of the heap by updating arena_used, allocate an
// object from this new region, and publish a pointer to that object,
// but for tracing running on another processor to observe the pointer
// but use the old value of arena_used. In this case, tracing will not
// mark the object, even though it's reachable. However, the mutator
// is guaranteed to execute a write barrier when it publishes the
// pointer, so it will take care of marking the object. A general
// consequence of this is that the garbage collector may cache the
// value of mheap_.arena_used. (See issue #9984.)
//
//
// Stack writes:
//
// The compiler omits write barriers for writes to the current frame,
// but if a stack pointer has been passed down the call stack, the
// compiler will generate a write barrier for writes through that
// pointer (because it doesn't know it's not a heap pointer).
//
// One might be tempted to ignore the write barrier if slot points
// into to the stack. Don't do it! Mark termination only re-scans
// frames that have potentially been active since the concurrent scan,
// so it depends on write barriers to track changes to pointers in
// stack frames that have not been active. go:nowritebarrier
func gcmarkwb_m(slot *uintptr, ptr uintptr) {
	if writeBarrierEnabled {
		if ptr != 0 && inheap(ptr) {
			shade(ptr)
		}
	}
}

// Write barrier calls must not happen during critical GC and scheduler
// related operations. In particular there are times when the GC assumes
// that the world is stopped but scheduler related code is still being
// executed, dealing with syscalls, dealing with putting gs on runnable
// queues and so forth. This code can not execute write barriers because
// the GC might drop them on the floor. Stopping the world involves removing
// the p associated with an m. We use the fact that m.p == nil to indicate
// that we are in one these critical section and throw if the write is of
// a pointer to a heap object.
//go:nosplit
func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
	mp := acquirem()
	if mp.inwb || mp.dying > 0 {
		releasem(mp)
		return
	}
	systemstack(func() {
		if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) {
			throw("writebarrierptr_nostore1 called with mp.p == nil")
		}
		mp.inwb = true
		gcmarkwb_m(dst, src)
	})
	mp.inwb = false
	releasem(mp)
}

// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
// but if we do that, Go inserts a write barrier on *dst = src.
//go:nosplit
func writebarrierptr(dst *uintptr, src uintptr) {
	*dst = src
	if !writeBarrierEnabled {
		return
	}
	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
		systemstack(func() {
			print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
			throw("bad pointer in write barrier")
		})
	}
	writebarrierptr_nostore1(dst, src)
}

// Like writebarrierptr, but the store has already been applied.
// Do not reapply.
//go:nosplit
func writebarrierptr_nostore(dst *uintptr, src uintptr) {
	if !writeBarrierEnabled {
		return
	}
	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
		systemstack(func() { throw("bad pointer in write barrier") })
	}
	writebarrierptr_nostore1(dst, src)
}

//go:nosplit
func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
	writebarrierptr(&dst[0], src[0])
	dst[1] = src[1]
}

//go:nosplit
func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
	writebarrierptr(&dst[0], src[0])
	dst[1] = src[1]
	dst[2] = src[2]
}

//go:nosplit
func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
	writebarrierptr(&dst[0], src[0])
	writebarrierptr(&dst[1], src[1])
}

//go:generate go run wbfat_gen.go -- wbfat.go
//
// The above line generates multiword write barriers for
// all the combinations of ptr+scalar up to four words.
// The implementations are written to wbfat.go.

// typedmemmove copies a value of type t to dst from src.
//go:nosplit
func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
	memmove(dst, src, typ.size)
	if typ.kind&kindNoPointers != 0 {
		return
	}
	heapBitsBulkBarrier(uintptr(dst), typ.size)
}

//go:linkname reflect_typedmemmove reflect.typedmemmove
func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
	typedmemmove(typ, dst, src)
}

// typedmemmovepartial is like typedmemmove but assumes that
// dst and src point off bytes into the value and only copies size bytes.
//go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
	memmove(dst, src, size)
	if !writeBarrierEnabled || typ.kind&kindNoPointers != 0 || size < ptrSize || !inheap(uintptr(dst)) {
		return
	}

	if frag := -off & (ptrSize - 1); frag != 0 {
		dst = add(dst, frag)
		size -= frag
	}
	heapBitsBulkBarrier(uintptr(dst), size&^(ptrSize-1))
}

// callwritebarrier is invoked at the end of reflectcall, to execute
// write barrier operations to record the fact that a call's return
// values have just been copied to frame, starting at retoffset
// and continuing to framesize. The entire frame (not just the return
// values) is described by typ. Because the copy has already
// happened, we call writebarrierptr_nostore, and we must be careful
// not to be preempted before the write barriers have been run.
//go:nosplit
func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
	if !writeBarrierEnabled || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < ptrSize || !inheap(uintptr(frame)) {
		return
	}
	heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
}

//go:nosplit
func typedslicecopy(typ *_type, dst, src slice) int {
	// TODO(rsc): If typedslicecopy becomes faster than calling
	// typedmemmove repeatedly, consider using during func growslice.
	n := dst.len
	if n > src.len {
		n = src.len
	}
	if n == 0 {
		return 0
	}
	dstp := unsafe.Pointer(dst.array)
	srcp := unsafe.Pointer(src.array)

	if raceenabled {
		callerpc := getcallerpc(unsafe.Pointer(&typ))
		pc := funcPC(slicecopy)
		racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
		racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
	}

	// Note: No point in checking typ.kind&kindNoPointers here:
	// compiler only emits calls to typedslicecopy for types with pointers,
	// and growslice and reflect_typedslicecopy check for pointers
	// before calling typedslicecopy.
	if !writeBarrierEnabled {
		memmove(dstp, srcp, uintptr(n)*typ.size)
		return n
	}

	systemstack(func() {
		if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) {
			// Overlap with src before dst.
			// Copy backward, being careful not to move dstp/srcp
			// out of the array they point into.
			dstp = add(dstp, uintptr(n-1)*typ.size)
			srcp = add(srcp, uintptr(n-1)*typ.size)
			i := 0
			for {
				typedmemmove(typ, dstp, srcp)
				if i++; i >= n {
					break
				}
				dstp = add(dstp, -typ.size)
				srcp = add(srcp, -typ.size)
			}
		} else {
			// Copy forward, being careful not to move dstp/srcp
			// out of the array they point into.
			i := 0
			for {
				typedmemmove(typ, dstp, srcp)
				if i++; i >= n {
					break
				}
				dstp = add(dstp, typ.size)
				srcp = add(srcp, typ.size)
			}
		}
	})
	return int(n)
}

//go:linkname reflect_typedslicecopy reflect.typedslicecopy
func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
	if elemType.kind&kindNoPointers != 0 {
		n := dst.len
		if n > src.len {
			n = src.len
		}
		memmove(dst.array, src.array, uintptr(n)*elemType.size)
		return n
	}
	return typedslicecopy(elemType, dst, src)
}
<commit_msg>runtime: fix go:nowritebarrier annotation on gcmarkwb_m<commit_after>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Garbage collector: write barriers.
//
// For the concurrent garbage collector, the Go compiler implements
// updates to pointer-valued fields that may be in heap objects by
// emitting calls to write barriers. This file contains the actual write barrier
// implementation, markwb, and the various wrappers called by the
// compiler to implement pointer assignment, slice assignment,
// typed memmove, and so on.

package runtime

import "unsafe"

// markwb is the mark-phase write barrier, the only barrier we have.
// The rest of this file exists only to make calls to this function.
//
// This is the Dijkstra barrier coarsened to always shade the ptr (dst) object.
// The original Dijkstra barrier only shaded ptrs being placed in black slots.
//
// Shade indicates that it has seen a white pointer by adding the referent
// to wbuf as well as marking it.
//
// slot is the destination (dst) in go code
// ptr is the value that goes into the slot (src) in the go code
//
//
// Dealing with memory ordering:
//
// Dijkstra pointed out that maintaining the no black to white
// pointers means that white to white pointers not need
// to be noted by the write barrier. Furthermore if either
// white object dies before it is reached by the
// GC then the object can be collected during this GC cycle
// instead of waiting for the next cycle. Unfortunately the cost of
// ensure that the object holding the slot doesn't concurrently
// change to black without the mutator noticing seems prohibitive.
//
// Consider the following example where the mutator writes into
// a slot and then loads the slot's mark bit while the GC thread
// writes to the slot's mark bit and then as part of scanning reads
// the slot.
//
// Initially both [slot] and [slotmark] are 0 (nil)
// Mutator thread          GC thread
// st [slot], ptr          st [slotmark], 1
//
// ld r1, [slotmark]       ld r2, [slot]
//
// Without an expensive memory barrier between the st and the ld, the final
// result on most HW (including 386/amd64) can be r1==r2==0. This is a classic
// example of what can happen when loads are allowed to be reordered with older
// stores (avoiding such reorderings lies at the heart of the classic
// Peterson/Dekker algorithms for mutual exclusion). Rather than require memory
// barriers, which will slow down both the mutator and the GC, we always grey
// the ptr object regardless of the slot's color.
//
// Another place where we intentionally omit memory barriers is when
// accessing mheap_.arena_used to check if a pointer points into the
// heap. On relaxed memory machines, it's possible for a mutator to
// extend the size of the heap by updating arena_used, allocate an
// object from this new region, and publish a pointer to that object,
// but for tracing running on another processor to observe the pointer
// but use the old value of arena_used. In this case, tracing will not
// mark the object, even though it's reachable. However, the mutator
// is guaranteed to execute a write barrier when it publishes the
// pointer, so it will take care of marking the object. A general
// consequence of this is that the garbage collector may cache the
// value of mheap_.arena_used. (See issue #9984.)
//
//
// Stack writes:
//
// The compiler omits write barriers for writes to the current frame,
// but if a stack pointer has been passed down the call stack, the
// compiler will generate a write barrier for writes through that
// pointer (because it doesn't know it's not a heap pointer).
//
// One might be tempted to ignore the write barrier if slot points
// into to the stack. Don't do it! Mark termination only re-scans
// frames that have potentially been active since the concurrent scan,
// so it depends on write barriers to track changes to pointers in
// stack frames that have not been active.
//go:nowritebarrier
func gcmarkwb_m(slot *uintptr, ptr uintptr) {
	if writeBarrierEnabled {
		if ptr != 0 && inheap(ptr) {
			shade(ptr)
		}
	}
}

// Write barrier calls must not happen during critical GC and scheduler
// related operations. In particular there are times when the GC assumes
// that the world is stopped but scheduler related code is still being
// executed, dealing with syscalls, dealing with putting gs on runnable
// queues and so forth. This code can not execute write barriers because
// the GC might drop them on the floor. Stopping the world involves removing
// the p associated with an m. We use the fact that m.p == nil to indicate
// that we are in one these critical section and throw if the write is of
// a pointer to a heap object.
//go:nosplit
func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
	mp := acquirem()
	if mp.inwb || mp.dying > 0 {
		releasem(mp)
		return
	}
	systemstack(func() {
		if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) {
			throw("writebarrierptr_nostore1 called with mp.p == nil")
		}
		mp.inwb = true
		gcmarkwb_m(dst, src)
	})
	mp.inwb = false
	releasem(mp)
}

// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
// but if we do that, Go inserts a write barrier on *dst = src.
//go:nosplit
func writebarrierptr(dst *uintptr, src uintptr) {
	*dst = src
	if !writeBarrierEnabled {
		return
	}
	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
		systemstack(func() {
			print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
			throw("bad pointer in write barrier")
		})
	}
	writebarrierptr_nostore1(dst, src)
}

// Like writebarrierptr, but the store has already been applied.
// Do not reapply.
//go:nosplit
func writebarrierptr_nostore(dst *uintptr, src uintptr) {
	if !writeBarrierEnabled {
		return
	}
	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
		systemstack(func() { throw("bad pointer in write barrier") })
	}
	writebarrierptr_nostore1(dst, src)
}

//go:nosplit
func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
	writebarrierptr(&dst[0], src[0])
	dst[1] = src[1]
}

//go:nosplit
func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
	writebarrierptr(&dst[0], src[0])
	dst[1] = src[1]
	dst[2] = src[2]
}

//go:nosplit
func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
	writebarrierptr(&dst[0], src[0])
	writebarrierptr(&dst[1], src[1])
}

//go:generate go run wbfat_gen.go -- wbfat.go
//
// The above line generates multiword write barriers for
// all the combinations of ptr+scalar up to four words.
// The implementations are written to wbfat.go.

// typedmemmove copies a value of type t to dst from src.
//go:nosplit
func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
	memmove(dst, src, typ.size)
	if typ.kind&kindNoPointers != 0 {
		return
	}
	heapBitsBulkBarrier(uintptr(dst), typ.size)
}

//go:linkname reflect_typedmemmove reflect.typedmemmove
func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
	typedmemmove(typ, dst, src)
}

// typedmemmovepartial is like typedmemmove but assumes that
// dst and src point off bytes into the value and only copies size bytes.
//go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
	memmove(dst, src, size)
	if !writeBarrierEnabled || typ.kind&kindNoPointers != 0 || size < ptrSize || !inheap(uintptr(dst)) {
		return
	}

	if frag := -off & (ptrSize - 1); frag != 0 {
		dst = add(dst, frag)
		size -= frag
	}
	heapBitsBulkBarrier(uintptr(dst), size&^(ptrSize-1))
}

// callwritebarrier is invoked at the end of reflectcall, to execute
// write barrier operations to record the fact that a call's return
// values have just been copied to frame, starting at retoffset
// and continuing to framesize. The entire frame (not just the return
// values) is described by typ. Because the copy has already
// happened, we call writebarrierptr_nostore, and we must be careful
// not to be preempted before the write barriers have been run.
//go:nosplit
func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
	if !writeBarrierEnabled || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < ptrSize || !inheap(uintptr(frame)) {
		return
	}
	heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
}

//go:nosplit
func typedslicecopy(typ *_type, dst, src slice) int {
	// TODO(rsc): If typedslicecopy becomes faster than calling
	// typedmemmove repeatedly, consider using during func growslice.
	n := dst.len
	if n > src.len {
		n = src.len
	}
	if n == 0 {
		return 0
	}
	dstp := unsafe.Pointer(dst.array)
	srcp := unsafe.Pointer(src.array)

	if raceenabled {
		callerpc := getcallerpc(unsafe.Pointer(&typ))
		pc := funcPC(slicecopy)
		racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
		racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
	}

	// Note: No point in checking typ.kind&kindNoPointers here:
	// compiler only emits calls to typedslicecopy for types with pointers,
	// and growslice and reflect_typedslicecopy check for pointers
	// before calling typedslicecopy.
	if !writeBarrierEnabled {
		memmove(dstp, srcp, uintptr(n)*typ.size)
		return n
	}

	systemstack(func() {
		if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) {
			// Overlap with src before dst.
			// Copy backward, being careful not to move dstp/srcp
			// out of the array they point into.
			dstp = add(dstp, uintptr(n-1)*typ.size)
			srcp = add(srcp, uintptr(n-1)*typ.size)
			i := 0
			for {
				typedmemmove(typ, dstp, srcp)
				if i++; i >= n {
					break
				}
				dstp = add(dstp, -typ.size)
				srcp = add(srcp, -typ.size)
			}
		} else {
			// Copy forward, being careful not to move dstp/srcp
			// out of the array they point into.
			i := 0
			for {
				typedmemmove(typ, dstp, srcp)
				if i++; i >= n {
					break
				}
				dstp = add(dstp, typ.size)
				srcp = add(srcp, typ.size)
			}
		}
	})
	return int(n)
}

//go:linkname reflect_typedslicecopy reflect.typedslicecopy
func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
	if elemType.kind&kindNoPointers != 0 {
		n := dst.len
		if n > src.len {
			n = src.len
		}
		memmove(dst.array, src.array, uintptr(n)*elemType.size)
		return n
	}
	return typedslicecopy(elemType, dst, src)
}
<|endoftext|>


<commit_before>package http_test

import (
	"errors"
	"fmt"
	"io"
	. "net/http"
	"os"
	"sync"
	"testing"
	"time"
)

func TestResponseControllerFlush(t *testing.T) { run(t, testResponseControllerFlush) }
func testResponseControllerFlush(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	continuec := make(chan struct{})
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		w.Write([]byte("one"))
		if err := ctl.Flush(); err != nil {
			t.Errorf("ctl.Flush() = %v, want nil", err)
			return
		}
		<-continuec
		w.Write([]byte("two"))
	}))

	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()

	buf := make([]byte, 16)
	n, err := res.Body.Read(buf)
	close(continuec)
	if err != nil || string(buf[:n]) != "one" {
		t.Fatalf("Body.Read = %q, %v, want %q, nil", string(buf[:n]), err, "one")
	}

	got, err := io.ReadAll(res.Body)
	if err != nil || string(got) != "two" {
		t.Fatalf("Body.Read = %q, %v, want %q, nil", string(got), err, "two")
	}
}

func TestResponseControllerHijack(t *testing.T) { run(t, testResponseControllerHijack) }
func testResponseControllerHijack(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	const header = "X-Header"
	const value = "set"
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		c, _, err := ctl.Hijack()
		if mode == http2Mode {
			if err == nil {
				t.Errorf("ctl.Hijack = nil, want error")
			}
			w.Header().Set(header, value)
			return
		}
		if err != nil {
			t.Errorf("ctl.Hijack = _, _, %v, want _, _, nil", err)
			return
		}
		fmt.Fprintf(c, "HTTP/1.0 200 OK\r\n%v: %v\r\nContent-Length: 0\r\n\r\n", header, value)
	}))
	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if got, want := res.Header.Get(header), value; got != want {
		t.Errorf("response header %q = %q, want %q", header, got, want)
	}
}

func TestResponseControllerSetPastWriteDeadline(t *testing.T) {
	run(t, testResponseControllerSetPastWriteDeadline)
}
func testResponseControllerSetPastWriteDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		w.Write([]byte("one"))
		if err := ctl.Flush(); err != nil {
			t.Errorf("before setting deadline: ctl.Flush() = %v, want nil", err)
		}
		if err := ctl.SetWriteDeadline(time.Now()); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}

		w.Write([]byte("two"))
		if err := ctl.Flush(); err == nil {
			t.Errorf("after setting deadline: ctl.Flush() = nil, want non-nil")
		}
		// Connection errors are sticky, so resetting the deadline does not permit
		// making more progress. We might want to change this in the future, but verify
		// the current behavior for now. If we do change this, we'll want to make sure
		// to do so only for writing the response body, not headers.
		if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Hour)); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
		w.Write([]byte("three"))
		if err := ctl.Flush(); err == nil {
			t.Errorf("after resetting deadline: ctl.Flush() = nil, want non-nil")
		}
	}))

	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
	b, _ := io.ReadAll(res.Body)
	if string(b) != "one" {
		t.Errorf("unexpected body: %q", string(b))
	}
}

func TestResponseControllerSetFutureWriteDeadline(t *testing.T) {
	run(t, testResponseControllerSetFutureWriteDeadline)
}
func testResponseControllerSetFutureWriteDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	errc := make(chan error, 1)
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
		_, err := io.Copy(w, neverEnding('a'))
		errc <- err
	}))

	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
	_, err = io.Copy(io.Discard, res.Body)
	if err == nil {
		t.Errorf("client reading from truncated request body: got nil error, want non-nil")
	}
	err = <-errc // io.Copy error
	if !errors.Is(err, os.ErrDeadlineExceeded) {
		t.Errorf("server timed out writing request body: got err %v; want os.ErrDeadlineExceeded", err)
	}
}

func TestResponseControllerSetPastReadDeadline(t *testing.T) {
	run(t, testResponseControllerSetPastReadDeadline)
}
func testResponseControllerSetPastReadDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	readc := make(chan struct{})
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		b := make([]byte, 3)
		n, err := io.ReadFull(r.Body, b)
		b = b[:n]
		if err != nil || string(b) != "one" {
			t.Errorf("before setting read deadline: Read = %v, %q, want nil, %q", err, string(b), "one")
			return
		}
		if err := ctl.SetReadDeadline(time.Now()); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
			return
		}
		b, err = io.ReadAll(r.Body)
		if err == nil || string(b) != "" {
			t.Errorf("after setting read deadline: Read = %q, nil, want error", string(b))
		}
		close(readc)
		// Connection errors are sticky, so resetting the deadline does not permit
		// making more progress. We might want to change this in the future, but verify
		// the current behavior for now.
		if err := ctl.SetReadDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
			return
		}
		b, err = io.ReadAll(r.Body)
		if err == nil {
			t.Errorf("after resetting read deadline: Read = %q, nil, want error", string(b))
		}
	}))

	pr, pw := io.Pipe()
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		pw.Write([]byte("one"))
		<-readc
		pw.Write([]byte("two"))
		pw.Close()
	}()
	defer wg.Wait()
	res, err := cst.c.Post(cst.ts.URL, "text/foo", pr)
	if err == nil {
		defer res.Body.Close()
	}
}

func TestResponseControllerSetFutureReadDeadline(t *testing.T) {
	run(t, testResponseControllerSetFutureReadDeadline)
}
func testResponseControllerSetFutureReadDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	respBody := "response body"
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
		ctl := NewResponseController(w)
		if err := ctl.SetReadDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
		}
		_, err := io.Copy(io.Discard, req.Body)
		if !errors.Is(err, os.ErrDeadlineExceeded) {
			t.Errorf("server timed out reading request body: got err %v; want os.ErrDeadlineExceeded", err)
		}
		w.Write([]byte(respBody))
	}))
	pr, pw := io.Pipe()
	res, err := cst.c.Post(cst.ts.URL, "text/apocryphal", pr)
	if err != nil {
		t.Fatal(err)
	}
	defer res.Body.Close()
	got, err := io.ReadAll(res.Body)
	if string(got) != respBody || err != nil {
		t.Errorf("client read response body: %q, %v; want %q, nil", string(got), err, respBody)
	}
	pw.Close()
}

type wrapWriter struct {
	ResponseWriter
}

func (w wrapWriter) Unwrap() ResponseWriter {
	return w.ResponseWriter
}

func TestWrappedResponseController(t *testing.T) { run(t, testWrappedResponseController) }
func testWrappedResponseController(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		if err := ctl.Flush(); err != nil {
			t.Errorf("ctl.Flush() = %v, want nil", err)
		}
		if err := ctl.SetReadDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
		}
		if err := ctl.SetWriteDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
	}))
	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
}
<commit_msg>net/http: deflake TestResponseControllerSetFutureWriteDeadline<commit_after>package http_test

import (
	"errors"
	"fmt"
	"io"
	. "net/http"
	"os"
	"sync"
	"testing"
	"time"
)

func TestResponseControllerFlush(t *testing.T) { run(t, testResponseControllerFlush) }
func testResponseControllerFlush(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	continuec := make(chan struct{})
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		w.Write([]byte("one"))
		if err := ctl.Flush(); err != nil {
			t.Errorf("ctl.Flush() = %v, want nil", err)
			return
		}
		<-continuec
		w.Write([]byte("two"))
	}))

	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()

	buf := make([]byte, 16)
	n, err := res.Body.Read(buf)
	close(continuec)
	if err != nil || string(buf[:n]) != "one" {
		t.Fatalf("Body.Read = %q, %v, want %q, nil", string(buf[:n]), err, "one")
	}

	got, err := io.ReadAll(res.Body)
	if err != nil || string(got) != "two" {
		t.Fatalf("Body.Read = %q, %v, want %q, nil", string(got), err, "two")
	}
}

func TestResponseControllerHijack(t *testing.T) { run(t, testResponseControllerHijack) }
func testResponseControllerHijack(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	const header = "X-Header"
	const value = "set"
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		c, _, err := ctl.Hijack()
		if mode == http2Mode {
			if err == nil {
				t.Errorf("ctl.Hijack = nil, want error")
			}
			w.Header().Set(header, value)
			return
		}
		if err != nil {
			t.Errorf("ctl.Hijack = _, _, %v, want _, _, nil", err)
			return
		}
		fmt.Fprintf(c, "HTTP/1.0 200 OK\r\n%v: %v\r\nContent-Length: 0\r\n\r\n", header, value)
	}))
	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if got, want := res.Header.Get(header), value; got != want {
		t.Errorf("response header %q = %q, want %q", header, got, want)
	}
}

func TestResponseControllerSetPastWriteDeadline(t *testing.T) {
	run(t, testResponseControllerSetPastWriteDeadline)
}
func testResponseControllerSetPastWriteDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		w.Write([]byte("one"))
		if err := ctl.Flush(); err != nil {
			t.Errorf("before setting deadline: ctl.Flush() = %v, want nil", err)
		}
		if err := ctl.SetWriteDeadline(time.Now()); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}

		w.Write([]byte("two"))
		if err := ctl.Flush(); err == nil {
			t.Errorf("after setting deadline: ctl.Flush() = nil, want non-nil")
		}
		// Connection errors are sticky, so resetting the deadline does not permit
		// making more progress. We might want to change this in the future, but verify
		// the current behavior for now. If we do change this, we'll want to make sure
		// to do so only for writing the response body, not headers.
		if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Hour)); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
		w.Write([]byte("three"))
		if err := ctl.Flush(); err == nil {
			t.Errorf("after resetting deadline: ctl.Flush() = nil, want non-nil")
		}
	}))

	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
	b, _ := io.ReadAll(res.Body)
	if string(b) != "one" {
		t.Errorf("unexpected body: %q", string(b))
	}
}

func TestResponseControllerSetFutureWriteDeadline(t *testing.T) {
	run(t, testResponseControllerSetFutureWriteDeadline)
}
func testResponseControllerSetFutureWriteDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	errc := make(chan error, 1)
	startwritec := make(chan struct{})
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		w.WriteHeader(200)
		if err := ctl.Flush(); err != nil {
			t.Errorf("ctl.Flush() = %v, want nil", err)
		}
		<-startwritec // don't set the deadline until the client reads response headers
		if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
		_, err := io.Copy(w, neverEnding('a'))
		errc <- err
	}))

	res, err := cst.c.Get(cst.ts.URL)
	close(startwritec)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
	_, err = io.Copy(io.Discard, res.Body)
	if err == nil {
		t.Errorf("client reading from truncated request body: got nil error, want non-nil")
	}
	err = <-errc // io.Copy error
	if !errors.Is(err, os.ErrDeadlineExceeded) {
		t.Errorf("server timed out writing request body: got err %v; want os.ErrDeadlineExceeded", err)
	}
}

func TestResponseControllerSetPastReadDeadline(t *testing.T) {
	run(t, testResponseControllerSetPastReadDeadline)
}
func testResponseControllerSetPastReadDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	readc := make(chan struct{})
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		b := make([]byte, 3)
		n, err := io.ReadFull(r.Body, b)
		b = b[:n]
		if err != nil || string(b) != "one" {
			t.Errorf("before setting read deadline: Read = %v, %q, want nil, %q", err, string(b), "one")
			return
		}
		if err := ctl.SetReadDeadline(time.Now()); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
			return
		}
		b, err = io.ReadAll(r.Body)
		if err == nil || string(b) != "" {
			t.Errorf("after setting read deadline: Read = %q, nil, want error", string(b))
		}
		close(readc)
		// Connection errors are sticky, so resetting the deadline does not permit
		// making more progress. We might want to change this in the future, but verify
		// the current behavior for now.
		if err := ctl.SetReadDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
			return
		}
		b, err = io.ReadAll(r.Body)
		if err == nil {
			t.Errorf("after resetting read deadline: Read = %q, nil, want error", string(b))
		}
	}))

	pr, pw := io.Pipe()
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		pw.Write([]byte("one"))
		<-readc
		pw.Write([]byte("two"))
		pw.Close()
	}()
	defer wg.Wait()
	res, err := cst.c.Post(cst.ts.URL, "text/foo", pr)
	if err == nil {
		defer res.Body.Close()
	}
}

func TestResponseControllerSetFutureReadDeadline(t *testing.T) {
	run(t, testResponseControllerSetFutureReadDeadline)
}
func testResponseControllerSetFutureReadDeadline(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	respBody := "response body"
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
		ctl := NewResponseController(w)
		if err := ctl.SetReadDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
		}
		_, err := io.Copy(io.Discard, req.Body)
		if !errors.Is(err, os.ErrDeadlineExceeded) {
			t.Errorf("server timed out reading request body: got err %v; want os.ErrDeadlineExceeded", err)
		}
		w.Write([]byte(respBody))
	}))
	pr, pw := io.Pipe()
	res, err := cst.c.Post(cst.ts.URL, "text/apocryphal", pr)
	if err != nil {
		t.Fatal(err)
	}
	defer res.Body.Close()
	got, err := io.ReadAll(res.Body)
	if string(got) != respBody || err != nil {
		t.Errorf("client read response body: %q, %v; want %q, nil", string(got), err, respBody)
	}
	pw.Close()
}

type wrapWriter struct {
	ResponseWriter
}

func (w wrapWriter) Unwrap() ResponseWriter {
	return w.ResponseWriter
}

func TestWrappedResponseController(t *testing.T) { run(t, testWrappedResponseController) }
func testWrappedResponseController(t *testing.T, mode testMode) {
	if mode == http2Mode {
		t.Skip("skip until h2_bundle.go is updated")
	}
	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
		ctl := NewResponseController(w)
		if err := ctl.Flush(); err != nil {
			t.Errorf("ctl.Flush() = %v, want nil", err)
		}
		if err := ctl.SetReadDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
		}
		if err := ctl.SetWriteDeadline(time.Time{}); err != nil {
			t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
		}
	}))
	res, err := cst.c.Get(cst.ts.URL)
	if err != nil {
		t.Fatalf("unexpected connection error: %v", err)
	}
	defer res.Body.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"time"
)

func main() {
	keyword, count := args()
	urls := fetchUrls(keyword, count)
	if len(urls) == 0 {
		fmt.Println("no image found")
		return
	}

	html := generateHtml(urls)
	openHtml(html)
}

func args() (keyword string, count int) {
	flag.StringVar(&keyword, "k", "yuyushiki", "keyword")
	flag.IntVar(&count, "c", 8, "count")
	flag.Parse()

	return keyword, count
}

func fetchUrls(keyword string, count int) (urls []string) {
	page := 1
	var _urls []string
	for len(urls) <= count {
		_urls = search(page, keyword)

		if len(_urls) == 0 {
			return urls
		}

		urls = append(urls, _urls...)
		page += 1
	}

	return urls
}

func generateHtml(urls []string) (html string) {
	html = "<!DOCTYPE HTML>"
	for _, url := range urls {
		html = html + ""
	}
	html = html + ""
	return html
}

func openHtml(html string) {
	file, err := ioutil.TempFile(os.TempDir(), "animegif")
	printError(err)
	ioutil.WriteFile(file.Name(), []byte(html), 0644)
	exec.Command("open", file.Name()).Start()
	time.Sleep(time.Second * 1)

	defer os.Remove(file.Name())
}

func printError(err error) {
	if err != nil {
		panic(err)
	}
}

type ResultType struct {
	Url string `json:"url"`
}

type ResponseDataType struct {
	Results []ResultType `json:"results"`
}

type ResponseType struct {
	ResponseData ResponseDataType `json:"responseData"`
}

func search(page int, keyword string) (urls []string) {
	perPage := 8
	base := "http://ajax.googleapis.com/ajax/services/search/images?"
	start := (page-1)*perPage + 1

	params := url.Values{
		"q":             {keyword},
		"rsz":           {fmt.Sprint(perPage)},
		"safe":          {"off"},
		"v":             {"1.0"},
		"as_filetype":   {"gif"},
		"imgsz":         {"large"},
		"start":         {fmt.Sprint(start)},
		"as_sitesearch": {"tumblr.com"},
	}

	body := openUrl(base + params.Encode())

	var response ResponseType
	err := json.Unmarshal(body, &response)
	printError(err)
	for _, value := range response.ResponseData.Results {
		urls = append(urls, value.Url)
	}
	return urls
}

func openUrl(req string) (body []byte) {
	res, err := http.Get(req)
	printError(err)
	defer res.Body.Close()

	body, err = ioutil.ReadAll(res.Body)
	printError(err)
	return body
}
<commit_msg>Fix a count bug<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"time"
)

func main() {
	keyword, count := args()
	urls := fetchUrls(keyword, count)
	if len(urls) == 0 {
		fmt.Println("no image found")
		return
	}

	html := generateHtml(urls)
	openHtml(html)
}

func args() (keyword string, count int) {
	flag.StringVar(&keyword, "k", "yuyushiki", "keyword")
	flag.IntVar(&count, "c", 8, "count")
	flag.Parse()

	return keyword, count
}

func fetchUrls(keyword string, count int) (urls []string) {
	page := 1
	var _urls []string
	for len(urls) < count {
		_urls = search(page, keyword)

		if len(_urls) == 0 {
			return urls
		}

		urls = append(urls, _urls...)
		page += 1
	}

	return urls
}

func generateHtml(urls []string) (html string) {
	html = "<!DOCTYPE HTML>"
	for _, url := range urls {
		html = html + ""
	}
	html = html + ""
	return html
}

func openHtml(html string) {
	file, err := ioutil.TempFile(os.TempDir(), "animegif")
	printError(err)
	ioutil.WriteFile(file.Name(), []byte(html), 0644)
	exec.Command("open", file.Name()).Start()
	time.Sleep(time.Second * 1)

	defer os.Remove(file.Name())
}

func printError(err error) {
	if err != nil {
		panic(err)
	}
}

type ResultType struct {
	Url string `json:"url"`
}

type ResponseDataType struct {
	Results []ResultType `json:"results"`
}

type ResponseType struct {
	ResponseData ResponseDataType `json:"responseData"`
}

func search(page int, keyword string) (urls []string) {
	perPage := 8
	base := "http://ajax.googleapis.com/ajax/services/search/images?"
	start := (page-1)*perPage + 1

	params := url.Values{
		"q":             {keyword},
		"rsz":           {fmt.Sprint(perPage)},
		"safe":          {"off"},
		"v":             {"1.0"},
		"as_filetype":   {"gif"},
		"imgsz":         {"large"},
		"start":         {fmt.Sprint(start)},
		"as_sitesearch": {"tumblr.com"},
	}

	body := openUrl(base + params.Encode())

	var response ResponseType
	err := json.Unmarshal(body, &response)
	printError(err)
	for _, value := range response.ResponseData.Results {
		urls = append(urls, value.Url)
	}
	return urls
}

func openUrl(req string) (body []byte) {
	res, err := http.Get(req)
	printError(err)
	defer res.Body.Close()

	body, err = ioutil.ReadAll(res.Body)
	printError(err)
	return body
}
<|endoftext|>